blob: 7b2882813c1ffea9a592fb1a42c8844e8e9301c2 [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
1471 CacheType
1472 type;
1473
1474 assert(cache != (Cache) NULL);
1475 cache_info=(CacheInfo *) cache;
1476 assert(cache_info->signature == MagickSignature);
1477 if (cache_info->debug != MagickFalse)
1478 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1479 cache_info->filename);
1480 (void) LockSemaphoreInfo(cache_info->semaphore);
1481 cache_info->reference_count--;
1482 if (cache_info->reference_count != 0)
1483 {
1484 (void) UnlockSemaphoreInfo(cache_info->semaphore);
1485 return((Cache) NULL);
1486 }
1487 (void) UnlockSemaphoreInfo(cache_info->semaphore);
1488 if (cache_resources != (SplayTreeInfo *) NULL)
1489 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1490 type=cache_info->type;
1491 RelinquishPixelCachePixels(cache_info);
1492 if ((type == MapCache) || (type == DiskCache))
1493 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1494 *cache_info->cache_filename='\0';
1495 if (cache_info->nexus_info != (NexusInfo **) NULL)
1496 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1497 cache_info->number_threads);
1498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
1507 if (cache_info->random_info != (RandomInfo *) NULL)
1508 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1509 cache_info->signature=(~MagickSignature);
1510 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1511 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1512 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1513 DestroySemaphoreInfo(&cache_info->semaphore);
1514 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1515 cache=(Cache) NULL;
1516 return(cache);
1517}
1518
1519/*
1520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521% %
1522% %
1523% %
1524+ D e s t r o y P i x e l C a c h e N e x u s %
1525% %
1526% %
1527% %
1528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529%
1530% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1531%
1532% The format of the DestroyPixelCacheNexus() method is:
1533%
1534% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1535% const unsigned long number_threads)
1536%
1537% A description of each parameter follows:
1538%
1539% o nexus_info: the nexus to destroy.
1540%
1541% o number_threads: the number of nexus threads.
1542%
1543*/
1544
1545static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1546{
1547 if (nexus_info->mapped == MagickFalse)
1548 (void) RelinquishMagickMemory(nexus_info->cache);
1549 else
1550 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1551 nexus_info->cache=(PixelPacket *) NULL;
1552 nexus_info->pixels=(PixelPacket *) NULL;
1553 nexus_info->indexes=(IndexPacket *) NULL;
1554 nexus_info->length=0;
1555 nexus_info->mapped=MagickFalse;
1556}
1557
1558MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1559 const unsigned long number_threads)
1560{
1561 register long
1562 i;
1563
1564 assert(nexus_info != (NexusInfo **) NULL);
1565 for (i=0; i < (long) number_threads; i++)
1566 {
1567 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1568 RelinquishCacheNexusPixels(nexus_info[i]);
1569 nexus_info[i]->signature=(~MagickSignature);
1570 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1571 }
1572 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1573 return(nexus_info);
1574}
1575
1576/*
1577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1578% %
1579% %
1580% %
1581+ D e s t r o y P i x e l C a c h e R e s o u r c e s %
1582% %
1583% %
1584% %
1585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586%
1587% DestroyPixelCacheResources() destroys the cache resources.
1588%
1589% The format of the DestroyPixelCacheResources() method is:
1590%
1591% DestroyPixelCacheResources(void)
1592%
1593*/
1594MagickExport void DestroyPixelCacheResources(void)
1595{
1596 AcquireSemaphoreInfo(&cache_semaphore);
1597 if (cache_resources != (SplayTreeInfo *) NULL)
1598 cache_resources=DestroySplayTree(cache_resources);
1599 instantiate_cache=MagickFalse;
1600 RelinquishSemaphoreInfo(cache_semaphore);
1601 DestroySemaphoreInfo(&cache_semaphore);
1602}
1603
1604/*
1605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1606% %
1607% %
1608% %
1609+ 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 %
1610% %
1611% %
1612% %
1613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1614%
1615% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1616% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1617%
1618% The format of the GetAuthenticIndexesFromCache() method is:
1619%
1620% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1621%
1622% A description of each parameter follows:
1623%
1624% o image: the image.
1625%
1626*/
1627static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1628{
1629 CacheInfo
1630 *cache_info;
1631
1632 IndexPacket
1633 *indexes;
1634
1635 long
1636 id;
1637
1638 if (image->debug != MagickFalse)
1639 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1640 cache_info=(CacheInfo *) image->cache;
1641 id=GetOpenMPThreadId();
1642 assert(id < (long) cache_info->number_threads);
1643 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1644 return(indexes);
1645}
1646
1647/*
1648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1649% %
1650% %
1651% %
1652% G e t A u t h e n t i c I n d e x Q u e u e %
1653% %
1654% %
1655% %
1656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1657%
1658% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1659% indexes associated with the last call to QueueAuthenticPixels() or
1660% GetVirtualPixels(). NULL is returned if the black channel or colormap
1661% indexes are not available.
1662%
1663% The format of the GetAuthenticIndexQueue() method is:
1664%
1665% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1666%
1667% A description of each parameter follows:
1668%
1669% o image: the image.
1670%
1671*/
1672MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1673{
1674 CacheInfo
1675 *cache_info;
1676
1677 assert(image != (const Image *) NULL);
1678 assert(image->signature == MagickSignature);
1679 if (image->debug != MagickFalse)
1680 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1681 assert(image->cache != (Cache) NULL);
1682 cache_info=(CacheInfo *) image->cache;
1683 assert(cache_info->signature == MagickSignature);
1684 if (cache_info->methods.get_authentic_indexes_from_handler ==
1685 (GetAuthenticIndexesFromHandler) NULL)
1686 return((IndexPacket *) NULL);
1687 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1688}
1689
1690/*
1691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1692% %
1693% %
1694% %
1695+ 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 %
1696% %
1697% %
1698% %
1699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1700%
1701% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1702% disk pixel cache as defined by the geometry parameters. A pointer to the
1703% pixels is returned if the pixels are transferred, otherwise a NULL is
1704% returned.
1705%
1706% The format of the GetAuthenticPixelCacheNexus() method is:
1707%
1708% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1709% const long y,const unsigned long columns,const unsigned long rows,
1710% NexusInfo *nexus_info,ExceptionInfo *exception)
1711%
1712% A description of each parameter follows:
1713%
1714% o image: the image.
1715%
1716% o x,y,columns,rows: These values define the perimeter of a region of
1717% pixels.
1718%
1719% o nexus_info: the cache nexus to return.
1720%
1721% o exception: return any errors or warnings in this structure.
1722%
1723*/
1724
1725static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1726 NexusInfo *nexus_info)
1727{
1728 MagickOffsetType
1729 offset;
1730
1731 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1732 nexus_info->region.x;
1733 if (nexus_info->pixels != (cache_info->pixels+offset))
1734 return(MagickFalse);
1735 return(MagickTrue);
1736}
1737
1738MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1739 const long y,const unsigned long columns,const unsigned long rows,
1740 NexusInfo *nexus_info,ExceptionInfo *exception)
1741{
1742 CacheInfo
1743 *cache_info;
1744
1745 PixelPacket
1746 *pixels;
1747
1748 /*
1749 Transfer pixels from the cache.
1750 */
1751 assert(image != (Image *) NULL);
1752 assert(image->signature == MagickSignature);
1753 if (image->debug != MagickFalse)
1754 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1755 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1756 if (pixels == (PixelPacket *) NULL)
1757 return((PixelPacket *) NULL);
1758 cache_info=(CacheInfo *) image->cache;
1759 assert(cache_info->signature == MagickSignature);
1760 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1761 return(pixels);
1762 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1763 return((PixelPacket *) NULL);
1764 if (cache_info->active_index_channel != MagickFalse)
1765 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1766 return((PixelPacket *) NULL);
1767 return(pixels);
1768}
1769
1770/*
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772% %
1773% %
1774% %
1775+ 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 %
1776% %
1777% %
1778% %
1779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780%
1781% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1782% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1783%
1784% The format of the GetAuthenticPixelsFromCache() method is:
1785%
1786% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1787%
1788% A description of each parameter follows:
1789%
1790% o image: the image.
1791%
1792*/
1793static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1794{
1795 CacheInfo
1796 *cache_info;
1797
1798 long
1799 id;
1800
1801 PixelPacket
1802 *pixels;
1803
1804 if (image->debug != MagickFalse)
1805 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1806 cache_info=(CacheInfo *) image->cache;
1807 id=GetOpenMPThreadId();
1808 assert(id < (long) cache_info->number_threads);
1809 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1810 return(pixels);
1811}
1812
1813/*
1814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815% %
1816% %
1817% %
1818% G e t A u t h e n t i c P i x e l Q u e u e %
1819% %
1820% %
1821% %
1822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1823%
1824% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1825% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1826%
1827% The format of the GetAuthenticPixelQueue() method is:
1828%
1829% PixelPacket *GetAuthenticPixelQueue(const Image image)
1830%
1831% A description of each parameter follows:
1832%
1833% o image: the image.
1834%
1835*/
1836MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1837{
1838 CacheInfo
1839 *cache_info;
1840
1841 assert(image != (const Image *) NULL);
1842 assert(image->signature == MagickSignature);
1843 if (image->debug != MagickFalse)
1844 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1845 assert(image->cache != (Cache) NULL);
1846 cache_info=(CacheInfo *) image->cache;
1847 assert(cache_info->signature == MagickSignature);
1848 if (cache_info->methods.get_authentic_pixels_from_handler ==
1849 (GetAuthenticPixelsFromHandler) NULL)
1850 return((PixelPacket *) NULL);
1851 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1852}
1853
1854/*
1855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1856% %
1857% %
1858% %
1859% G e t A u t h e n t i c P i x e l s %
1860% %
1861% %
1862% %
1863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1864%
1865% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1866% region is successfully accessed, a pointer to a PixelPacket array
1867% representing the region is returned, otherwise NULL is returned.
1868%
1869% The returned pointer may point to a temporary working copy of the pixels
1870% or it may point to the original pixels in memory. Performance is maximized
1871% if the selected region is part of one row, or one or more full rows, since
1872% then there is opportunity to access the pixels in-place (without a copy)
1873% if the image is in RAM, or in a memory-mapped file. The returned pointer
1874% should *never* be deallocated by the user.
1875%
1876% Pixels accessed via the returned pointer represent a simple array of type
1877% PixelPacket. If the image type is CMYK or if the storage class is
1878% PseduoClass, call GetAuthenticIndexQueue() after invoking
1879% GetAuthenticPixels() to obtain the black color component or colormap indexes
1880% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1881% (and/or IndexPacket) array has been updated, the changes must be saved back
1882% to the underlying image using SyncAuthenticPixels() or they may be lost.
1883%
1884% The format of the GetAuthenticPixels() method is:
1885%
1886% PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1887% const unsigned long columns,const unsigned long rows,
1888% ExceptionInfo *exception)
1889%
1890% A description of each parameter follows:
1891%
1892% o image: the image.
1893%
1894% o x,y,columns,rows: These values define the perimeter of a region of
1895% pixels.
1896%
1897% o exception: return any errors or warnings in this structure.
1898%
1899*/
1900MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1901 const long y,const unsigned long columns,const unsigned long rows,
1902 ExceptionInfo *exception)
1903{
1904 CacheInfo
1905 *cache_info;
1906
1907 PixelPacket
1908 *pixels;
1909
1910 assert(image != (Image *) NULL);
1911 assert(image->signature == MagickSignature);
1912 if (image->debug != MagickFalse)
1913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1914 assert(image->cache != (Cache) NULL);
1915 cache_info=(CacheInfo *) image->cache;
1916 assert(cache_info->signature == MagickSignature);
1917 if (cache_info->methods.get_authentic_pixels_handler ==
1918 (GetAuthenticPixelsHandler) NULL)
1919 return((PixelPacket *) NULL);
1920 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1921 rows,exception);
1922 return(pixels);
1923}
1924
1925/*
1926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1927% %
1928% %
1929% %
1930+ G e t A u t h e n t i c P i x e l s C a c h e %
1931% %
1932% %
1933% %
1934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935%
1936% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1937% as defined by the geometry parameters. A pointer to the pixels is returned
1938% if the pixels are transferred, otherwise a NULL is returned.
1939%
1940% The format of the GetAuthenticPixelsCache() method is:
1941%
1942% PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1943% const long y,const unsigned long columns,const unsigned long rows,
1944% ExceptionInfo *exception)
1945%
1946% A description of each parameter follows:
1947%
1948% o image: the image.
1949%
1950% o x,y,columns,rows: These values define the perimeter of a region of
1951% pixels.
1952%
1953% o exception: return any errors or warnings in this structure.
1954%
1955*/
1956static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1957 const long y,const unsigned long columns,const unsigned long rows,
1958 ExceptionInfo *exception)
1959{
1960 CacheInfo
1961 *cache_info;
1962
1963 long
1964 id;
1965
1966 PixelPacket
1967 *pixels;
1968
1969 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
1970 if (cache_info == (Cache) NULL)
1971 return((PixelPacket *) NULL);
1972 id=GetOpenMPThreadId();
1973 assert(id < (long) cache_info->number_threads);
1974 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1975 cache_info->nexus_info[id],exception);
1976 return(pixels);
1977}
1978
1979/*
1980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981% %
1982% %
1983% %
1984+ G e t I m a g e E x t e n t %
1985% %
1986% %
1987% %
1988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989%
1990% GetImageExtent() returns the extent of the pixels associated with the
1991% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1992%
1993% The format of the GetImageExtent() method is:
1994%
1995% MagickSizeType GetImageExtent(const Image *image)
1996%
1997% A description of each parameter follows:
1998%
1999% o image: the image.
2000%
2001*/
2002MagickExport MagickSizeType GetImageExtent(const Image *image)
2003{
2004 CacheInfo
2005 *cache_info;
2006
2007 long
2008 id;
2009
2010 MagickSizeType
2011 extent;
2012
2013 assert(image != (Image *) NULL);
2014 assert(image->signature == MagickSignature);
2015 if (image->debug != MagickFalse)
2016 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2017 assert(image->cache != (Cache) NULL);
2018 cache_info=(CacheInfo *) image->cache;
2019 assert(cache_info->signature == MagickSignature);
2020 id=GetOpenMPThreadId();
2021 assert(id < (long) cache_info->number_threads);
2022 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2023 return(extent);
2024}
2025
2026/*
2027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2028% %
2029% %
2030% %
2031+ G e t I m a g e P i x e l C a c h e %
2032% %
2033% %
2034% %
2035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2036%
2037% GetImagePixelCache() ensures that there is only a single reference to the
2038% pixel cache to be modified, updating the provided cache pointer to point to
2039% a clone of the original pixel cache if necessary.
2040%
2041% The format of the GetImagePixelCache method is:
2042%
2043% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2044% ExceptionInfo *exception)
2045%
2046% A description of each parameter follows:
2047%
2048% o image: the image.
2049%
2050% o clone: any value other than MagickFalse clones the cache pixels.
2051%
2052% o exception: return any errors or warnings in this structure.
2053%
2054*/
2055
2056static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2057{
2058 CacheInfo
2059 *cache_info;
2060
2061 /*
2062 Does the image match the pixel cache morphology?
2063 */
2064 cache_info=(CacheInfo *) image->cache;
2065 if ((image->storage_class != cache_info->storage_class) ||
2066 (image->colorspace != cache_info->colorspace) ||
2067 (image->columns != cache_info->columns) ||
2068 (image->rows != cache_info->rows) ||
2069 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2070 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2071 return(MagickFalse);
2072 return(MagickTrue);
2073}
2074
2075MagickExport Cache GetImagePixelCache(Image *image,
2076 const MagickBooleanType clone,ExceptionInfo *exception)
2077{
2078 CacheInfo
2079 *cache_info;
2080
2081 MagickSizeType
2082 time_limit;
2083
2084 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002085 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002086 status;
2087
2088 if (image->debug != MagickFalse)
2089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2090 status=MagickTrue;
2091 (void) LockSemaphoreInfo(image->semaphore);
2092 time_limit=GetMagickResourceLimit(TimeResource);
2093 if (cache_timer == 0)
2094 cache_timer=time((time_t *) NULL);
2095 if ((time_limit != MagickResourceInfinity) &&
2096 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2097 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2098 assert(image->cache != (Cache) NULL);
2099 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002100 destroy=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002101 (void) LockSemaphoreInfo(cache_info->semaphore);
2102 if (cache_info->reference_count > 1)
2103 {
2104 Image
2105 clone_image;
2106
2107 CacheInfo
2108 *clone_info;
2109
2110 /*
2111 Clone pixel cache.
2112 */
2113 clone_image=(*image);
2114 clone_image.cache=ClonePixelCache(cache_info);
2115 clone_info=(CacheInfo *) clone_image.cache;
2116 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2117 if (status != MagickFalse)
2118 {
2119 status=OpenPixelCache(&clone_image,IOMode,exception);
2120 if (status != MagickFalse)
2121 {
2122 if (clone != MagickFalse)
2123 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2124 if (status != MagickFalse)
2125 {
cristy4320e0e2009-09-10 15:00:08 +00002126 destroy=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002127 image->cache=clone_image.cache;
2128 }
2129 }
2130 }
2131 }
2132 (void) UnlockSemaphoreInfo(cache_info->semaphore);
cristy4320e0e2009-09-10 15:00:08 +00002133 if (destroy != MagickFalse)
2134 DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002135 if (status != MagickFalse)
2136 {
2137 /*
2138 Ensure the image matches the pixel cache morphology.
2139 */
2140 image->taint=MagickTrue;
2141 image->type=UndefinedType;
2142 if (image->colorspace == GRAYColorspace)
2143 image->colorspace=RGBColorspace;
2144 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2145 status=OpenPixelCache(image,IOMode,exception);
2146 }
2147 (void) UnlockSemaphoreInfo(image->semaphore);
2148 if (status == MagickFalse)
2149 return((Cache) NULL);
2150 return(image->cache);
2151}
2152
2153/*
2154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155% %
2156% %
2157% %
2158% G e t O n e A u t h e n t i c P i x e l %
2159% %
2160% %
2161% %
2162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163%
2164% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2165% location. The image background color is returned if an error occurs.
2166%
2167% The format of the GetOneAuthenticPixel() method is:
2168%
2169% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2170% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2171%
2172% A description of each parameter follows:
2173%
2174% o image: the image.
2175%
2176% o x,y: These values define the location of the pixel to return.
2177%
2178% o pixel: return a pixel at the specified (x,y) location.
2179%
2180% o exception: return any errors or warnings in this structure.
2181%
2182*/
2183MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2184 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2185{
2186 CacheInfo
2187 *cache_info;
2188
2189 GetOneAuthenticPixelFromHandler
2190 get_one_authentic_pixel_from_handler;
2191
2192 MagickBooleanType
2193 status;
2194
2195 assert(image != (Image *) NULL);
2196 assert(image->signature == MagickSignature);
2197 if (image->debug != MagickFalse)
2198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2199 assert(image->cache != (Cache) NULL);
2200 cache_info=(CacheInfo *) image->cache;
2201 assert(cache_info->signature == MagickSignature);
2202 *pixel=image->background_color;
2203 get_one_authentic_pixel_from_handler=
2204 cache_info->methods.get_one_authentic_pixel_from_handler;
2205 if (get_one_authentic_pixel_from_handler ==
2206 (GetOneAuthenticPixelFromHandler) NULL)
2207 return(MagickFalse);
2208 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2209 pixel,exception);
2210 return(status);
2211}
2212
2213/*
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215% %
2216% %
2217% %
2218+ 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 %
2219% %
2220% %
2221% %
2222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223%
2224% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2225% location. The image background color is returned if an error occurs.
2226%
2227% The format of the GetOneAuthenticPixelFromCache() method is:
2228%
2229% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2230% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2231%
2232% A description of each parameter follows:
2233%
2234% o image: the image.
2235%
2236% o x,y: These values define the location of the pixel to return.
2237%
2238% o pixel: return a pixel at the specified (x,y) location.
2239%
2240% o exception: return any errors or warnings in this structure.
2241%
2242*/
2243static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2244 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2245{
2246 PixelPacket
2247 *pixels;
2248
2249 if (image->debug != MagickFalse)
2250 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2251 *pixel=image->background_color;
2252 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2253 if (pixels == (PixelPacket *) NULL)
2254 return(MagickFalse);
2255 *pixel=(*pixels);
2256 return(MagickTrue);
2257}
2258
2259/*
2260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261% %
2262% %
2263% %
2264% G e t O n e V i r t u a l M a g i c k P i x e l %
2265% %
2266% %
2267% %
2268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2269%
2270% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2271% location. The image background color is returned if an error occurs. If
2272% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2273%
2274% The format of the GetOneVirtualMagickPixel() method is:
2275%
2276% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2277% const long x,const long y,MagickPixelPacket *pixel,
2278% ExceptionInfo exception)
2279%
2280% A description of each parameter follows:
2281%
2282% o image: the image.
2283%
2284% o x,y: these values define the location of the pixel to return.
2285%
2286% o pixel: return a pixel at the specified (x,y) location.
2287%
2288% o exception: return any errors or warnings in this structure.
2289%
2290*/
2291MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2292 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2293{
2294 CacheInfo
2295 *cache_info;
2296
2297 register const IndexPacket
2298 *indexes;
2299
2300 register const PixelPacket
2301 *p;
2302
2303 assert(image != (const Image *) NULL);
2304 assert(image->signature == MagickSignature);
2305 assert(image->cache != (Cache) NULL);
2306 cache_info=(CacheInfo *) image->cache;
2307 assert(cache_info->signature == MagickSignature);
2308 GetMagickPixelPacket(image,pixel);
2309 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2310 exception);
2311 if (p == (const PixelPacket *) NULL)
2312 return(MagickFalse);
2313 indexes=GetVirtualIndexQueue(image);
2314 SetMagickPixelPacket(image,p,indexes,pixel);
2315 return(MagickTrue);
2316}
2317
2318/*
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320% %
2321% %
2322% %
2323% G e t O n e V i r t u a l M e t h o d P i x e l %
2324% %
2325% %
2326% %
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328%
2329% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2330% location as defined by specified pixel method. The image background color
2331% is returned if an error occurs. If you plan to modify the pixel, use
2332% GetOneAuthenticPixel() instead.
2333%
2334% The format of the GetOneVirtualMethodPixel() method is:
2335%
2336% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2337% const VirtualPixelMethod virtual_pixel_method,const long x,
2338% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2339%
2340% A description of each parameter follows:
2341%
2342% o image: the image.
2343%
2344% o virtual_pixel_method: the virtual pixel method.
2345%
2346% o x,y: These values define the location of the pixel to return.
2347%
2348% o pixel: return a pixel at the specified (x,y) location.
2349%
2350% o exception: return any errors or warnings in this structure.
2351%
2352*/
2353MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2354 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2355 PixelPacket *pixel,ExceptionInfo *exception)
2356{
2357 GetOneVirtualPixelFromHandler
2358 get_one_virtual_pixel_from_handler;
2359
2360 CacheInfo
2361 *cache_info;
2362
2363 MagickBooleanType
2364 status;
2365
2366 assert(image != (const Image *) NULL);
2367 assert(image->signature == MagickSignature);
2368 assert(image->cache != (Cache) NULL);
2369 cache_info=(CacheInfo *) image->cache;
2370 assert(cache_info->signature == MagickSignature);
2371 *pixel=image->background_color;
2372 get_one_virtual_pixel_from_handler=
2373 cache_info->methods.get_one_virtual_pixel_from_handler;
2374 if (get_one_virtual_pixel_from_handler ==
2375 (GetOneVirtualPixelFromHandler) NULL)
2376 return(MagickFalse);
2377 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2378 pixel,exception);
2379 return(status);
2380}
2381
2382/*
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384% %
2385% %
2386% %
2387% G e t O n e V i r t u a l P i x e l %
2388% %
2389% %
2390% %
2391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392%
2393% GetOneVirtualPixel() returns a single virtual pixel at the specified
2394% (x,y) location. The image background color is returned if an error occurs.
2395% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2396%
2397% The format of the GetOneVirtualPixel() method is:
2398%
2399% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2400% const long y,PixelPacket *pixel,ExceptionInfo exception)
2401%
2402% A description of each parameter follows:
2403%
2404% o image: the image.
2405%
2406% o x,y: These values define the location of the pixel to return.
2407%
2408% o pixel: return a pixel at the specified (x,y) location.
2409%
2410% o exception: return any errors or warnings in this structure.
2411%
2412*/
2413MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2414 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2415{
2416 GetOneVirtualPixelFromHandler
2417 get_one_virtual_pixel_from_handler;
2418
2419 CacheInfo
2420 *cache_info;
2421
2422 MagickBooleanType
2423 status;
2424
2425 assert(image != (const Image *) NULL);
2426 assert(image->signature == MagickSignature);
2427 assert(image->cache != (Cache) NULL);
2428 cache_info=(CacheInfo *) image->cache;
2429 assert(cache_info->signature == MagickSignature);
2430 *pixel=image->background_color;
2431 get_one_virtual_pixel_from_handler=
2432 cache_info->methods.get_one_virtual_pixel_from_handler;
2433 if (get_one_virtual_pixel_from_handler ==
2434 (GetOneVirtualPixelFromHandler) NULL)
2435 return(MagickFalse);
2436 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2437 image),x,y,pixel,exception);
2438 return(status);
2439}
2440
2441/*
2442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2443% %
2444% %
2445% %
2446+ 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 %
2447% %
2448% %
2449% %
2450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2451%
2452% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2453% specified (x,y) location. The image background color is returned if an
2454% error occurs.
2455%
2456% The format of the GetOneVirtualPixelFromCache() method is:
2457%
2458% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2459% const VirtualPixelPacket method,const long x,const long y,
2460% PixelPacket *pixel,ExceptionInfo *exception)
2461%
2462% A description of each parameter follows:
2463%
2464% o image: the image.
2465%
2466% o virtual_pixel_method: the virtual pixel method.
2467%
2468% o x,y: These values define the location of the pixel to return.
2469%
2470% o pixel: return a pixel at the specified (x,y) location.
2471%
2472% o exception: return any errors or warnings in this structure.
2473%
2474*/
2475static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2476 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2477 PixelPacket *pixel,ExceptionInfo *exception)
2478{
2479 const PixelPacket
2480 *pixels;
2481
2482 *pixel=image->background_color;
2483 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2484 if (pixels == (const PixelPacket *) NULL)
2485 return(MagickFalse);
2486 *pixel=(*pixels);
2487 return(MagickTrue);
2488}
2489
2490/*
2491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2492% %
2493% %
2494% %
2495+ G e t P i x e l C a c h e C o l o r s p a c e %
2496% %
2497% %
2498% %
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500%
2501% GetPixelCacheColorspace() returns the class type of the pixel cache.
2502%
2503% The format of the GetPixelCacheColorspace() method is:
2504%
2505% Colorspace GetPixelCacheColorspace(Cache cache)
2506%
2507% A description of each parameter follows:
2508%
2509% o cache: the pixel cache.
2510%
2511*/
2512MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2513{
2514 CacheInfo
2515 *cache_info;
2516
2517 assert(cache != (Cache) NULL);
2518 cache_info=(CacheInfo *) cache;
2519 assert(cache_info->signature == MagickSignature);
2520 if (cache_info->debug != MagickFalse)
2521 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2522 cache_info->filename);
2523 return(cache_info->colorspace);
2524}
2525
2526/*
2527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528% %
2529% %
2530% %
2531+ G e t P i x e l C a c h e M e t h o d s %
2532% %
2533% %
2534% %
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536%
2537% GetPixelCacheMethods() initializes the CacheMethods structure.
2538%
2539% The format of the GetPixelCacheMethods() method is:
2540%
2541% void GetPixelCacheMethods(CacheMethods *cache_methods)
2542%
2543% A description of each parameter follows:
2544%
2545% o cache_methods: Specifies a pointer to a CacheMethods structure.
2546%
2547*/
2548MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2549{
2550 assert(cache_methods != (CacheMethods *) NULL);
2551 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2552 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2553 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2554 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2555 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2556 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2557 cache_methods->get_authentic_indexes_from_handler=
2558 GetAuthenticIndexesFromCache;
2559 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2560 cache_methods->get_one_authentic_pixel_from_handler=
2561 GetOneAuthenticPixelFromCache;
2562 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2563 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2564 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2565}
2566
2567/*
2568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569% %
2570% %
2571% %
2572+ G e t P i x e l C a c h e N e x u s E x t e n t %
2573% %
2574% %
2575% %
2576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577%
2578% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2579% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2580%
2581% The format of the GetPixelCacheNexusExtent() method is:
2582%
2583% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2584% NexusInfo *nexus_info)
2585%
2586% A description of each parameter follows:
2587%
2588% o nexus_info: the nexus info.
2589%
2590*/
2591MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2592 NexusInfo *nexus_info)
2593{
2594 CacheInfo
2595 *cache_info;
2596
2597 MagickSizeType
2598 extent;
2599
2600 if (cache == (Cache) NULL)
2601 return(0);
2602 cache_info=(CacheInfo *) cache;
2603 assert(cache_info->signature == MagickSignature);
2604 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2605 if (extent == 0)
2606 return((MagickSizeType) cache_info->columns*cache_info->rows);
2607 return(extent);
2608}
2609
2610/*
2611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2612% %
2613% %
2614% %
2615+ 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 %
2616% %
2617% %
2618% %
2619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620%
2621% GetPixelCacheNexusIndexes() returns the indexes associated with the
2622% specified cache nexus.
2623%
2624% The format of the GetPixelCacheNexusIndexes() method is:
2625%
2626% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2627% NexusInfo *nexus_info)
2628%
2629% A description of each parameter follows:
2630%
2631% o cache: the pixel cache.
2632%
2633% o nexus_info: the cache nexus to return the colormap indexes.
2634%
2635*/
2636MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2637 NexusInfo *nexus_info)
2638{
2639 CacheInfo
2640 *cache_info;
2641
2642 if (cache == (Cache) NULL)
2643 return((IndexPacket *) NULL);
2644 cache_info=(CacheInfo *) cache;
2645 assert(cache_info->signature == MagickSignature);
2646 if (cache_info->storage_class == UndefinedClass)
2647 return((IndexPacket *) NULL);
2648 return(nexus_info->indexes);
2649}
2650
2651/*
2652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2653% %
2654% %
2655% %
2656+ G e t P i x e l C a c h e N e x u s P i x e l s %
2657% %
2658% %
2659% %
2660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2661%
2662% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2663% cache nexus.
2664%
2665% The format of the GetPixelCacheNexusPixels() method is:
2666%
2667% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2668% NexusInfo *nexus_info)
2669%
2670% A description of each parameter follows:
2671%
2672% o cache: the pixel cache.
2673%
2674% o nexus_info: the cache nexus to return the pixels.
2675%
2676*/
2677MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2678 NexusInfo *nexus_info)
2679{
2680 CacheInfo
2681 *cache_info;
2682
2683 if (cache == (Cache) NULL)
2684 return((PixelPacket *) NULL);
2685 cache_info=(CacheInfo *) cache;
2686 assert(cache_info->signature == MagickSignature);
2687 if (cache_info->debug != MagickFalse)
2688 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2689 cache_info->filename);
2690 if (cache_info->storage_class == UndefinedClass)
2691 return((PixelPacket *) NULL);
2692 return(nexus_info->pixels);
2693}
2694
2695/*
2696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2697% %
2698% %
2699% %
cristyb32b90a2009-09-07 21:45:48 +00002700+ 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 +00002701% %
2702% %
2703% %
2704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2705%
2706% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2707%
2708% The format of the GetPixelCacheStorageClass() method is:
2709%
2710% ClassType GetPixelCacheStorageClass(Cache cache)
2711%
2712% A description of each parameter follows:
2713%
2714% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2715%
2716% o cache: the pixel cache.
2717%
2718*/
2719MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2720{
2721 CacheInfo
2722 *cache_info;
2723
2724 assert(cache != (Cache) NULL);
2725 cache_info=(CacheInfo *) cache;
2726 assert(cache_info->signature == MagickSignature);
2727 if (cache_info->debug != MagickFalse)
2728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2729 cache_info->filename);
2730 return(cache_info->storage_class);
2731}
2732
2733/*
2734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735% %
2736% %
2737% %
cristyb32b90a2009-09-07 21:45:48 +00002738+ G e t P i x e l C a c h e T i l e S i z e %
2739% %
2740% %
2741% %
2742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743%
2744% GetPixelCacheTileSize() returns the pixel cache tile size.
2745%
2746% The format of the GetPixelCacheTileSize() method is:
2747%
2748% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2749% unsigned long *height)
2750%
2751% A description of each parameter follows:
2752%
2753% o image: the image.
2754%
2755% o width: the optimize cache tile width in pixels.
2756%
2757% o height: the optimize cache tile height in pixels.
2758%
2759*/
2760MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2761 unsigned long *height)
2762{
2763 CacheInfo
2764 *cache_info;
2765
2766 assert(image != (Image *) NULL);
2767 assert(image->signature == MagickSignature);
2768 if (image->debug != MagickFalse)
2769 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2770 assert(image->cache != (Cache) NULL);
2771 cache_info=(CacheInfo *) image->cache;
2772 assert(cache_info->signature == MagickSignature);
2773 *width=2048UL/sizeof(PixelPacket);
2774 if (GetPixelCacheType(image) == DiskCache)
2775 *width=8196UL/sizeof(PixelPacket);
2776 *height=(*width);
2777}
2778
2779/*
2780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2781% %
2782% %
2783% %
2784+ G e t P i x e l C a c h e T y p e %
2785% %
2786% %
2787% %
2788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2789%
2790% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2791%
2792% The format of the GetPixelCacheType() method is:
2793%
2794% CacheType GetPixelCacheType(const Image *image)
2795%
2796% A description of each parameter follows:
2797%
2798% o image: the image.
2799%
2800*/
2801MagickExport CacheType GetPixelCacheType(const Image *image)
2802{
2803 CacheInfo
2804 *cache_info;
2805
2806 assert(image != (Image *) NULL);
2807 assert(image->signature == MagickSignature);
2808 if (image->debug != MagickFalse)
2809 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2810 assert(image->cache != (Cache) NULL);
2811 cache_info=(CacheInfo *) image->cache;
2812 assert(cache_info->signature == MagickSignature);
2813 return(cache_info->type);
2814}
2815
2816/*
2817%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2818% %
2819% %
2820% %
cristy3ed852e2009-09-05 21:47:34 +00002821+ 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 %
2822% %
2823% %
2824% %
2825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2826%
2827% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2828% pixel cache. A virtual pixel is any pixel access that is outside the
2829% boundaries of the image cache.
2830%
2831% The format of the GetPixelCacheVirtualMethod() method is:
2832%
2833% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2834%
2835% A description of each parameter follows:
2836%
2837% o image: the image.
2838%
2839*/
2840MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2841{
2842 CacheInfo
2843 *cache_info;
2844
2845 assert(image != (Image *) NULL);
2846 assert(image->signature == MagickSignature);
2847 if (image->debug != MagickFalse)
2848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2849 assert(image->cache != (Cache) NULL);
2850 cache_info=(CacheInfo *) image->cache;
2851 assert(cache_info->signature == MagickSignature);
2852 return(cache_info->virtual_pixel_method);
2853}
2854
2855/*
2856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2857% %
2858% %
2859% %
2860+ 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 %
2861% %
2862% %
2863% %
2864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2865%
2866% GetVirtualIndexesFromCache() returns the indexes associated with the last
2867% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2868%
2869% The format of the GetVirtualIndexesFromCache() method is:
2870%
2871% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2872%
2873% A description of each parameter follows:
2874%
2875% o image: the image.
2876%
2877*/
2878static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2879{
2880 CacheInfo
2881 *cache_info;
2882
2883 const IndexPacket
2884 *indexes;
2885
2886 long
2887 id;
2888
2889 if (image->debug != MagickFalse)
2890 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2891 cache_info=(CacheInfo *) image->cache;
2892 id=GetOpenMPThreadId();
2893 assert(id < (long) cache_info->number_threads);
2894 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2895 return(indexes);
2896}
2897
2898/*
2899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2900% %
2901% %
2902% %
2903+ 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 %
2904% %
2905% %
2906% %
2907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2908%
2909% GetVirtualIndexesFromNexus() returns the indexes associated with the
2910% specified cache nexus.
2911%
2912% The format of the GetVirtualIndexesFromNexus() method is:
2913%
2914% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2915% NexusInfo *nexus_info)
2916%
2917% A description of each parameter follows:
2918%
2919% o cache: the pixel cache.
2920%
2921% o nexus_info: the cache nexus to return the colormap indexes.
2922%
2923*/
2924MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2925 NexusInfo *nexus_info)
2926{
2927 CacheInfo
2928 *cache_info;
2929
2930 if (cache == (Cache) NULL)
2931 return((IndexPacket *) NULL);
2932 cache_info=(CacheInfo *) cache;
2933 assert(cache_info->signature == MagickSignature);
2934 if (cache_info->storage_class == UndefinedClass)
2935 return((IndexPacket *) NULL);
2936 return(nexus_info->indexes);
2937}
2938
2939/*
2940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2941% %
2942% %
2943% %
2944% G e t V i r t u a l I n d e x Q u e u e %
2945% %
2946% %
2947% %
2948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949%
2950% GetVirtualIndexQueue() returns the virtual black channel or the
2951% colormap indexes associated with the last call to QueueAuthenticPixels() or
2952% GetVirtualPixels(). NULL is returned if the black channel or colormap
2953% indexes are not available.
2954%
2955% The format of the GetVirtualIndexQueue() method is:
2956%
2957% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2958%
2959% A description of each parameter follows:
2960%
2961% o image: the image.
2962%
2963*/
2964MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2965{
2966 CacheInfo
2967 *cache_info;
2968
2969 assert(image != (const Image *) NULL);
2970 assert(image->signature == MagickSignature);
2971 if (image->debug != MagickFalse)
2972 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2973 assert(image->cache != (Cache) NULL);
2974 cache_info=(CacheInfo *) image->cache;
2975 assert(cache_info->signature == MagickSignature);
2976 if (cache_info->methods.get_virtual_indexes_from_handler ==
2977 (GetVirtualIndexesFromHandler) NULL)
2978 return((IndexPacket *) NULL);
2979 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2980}
2981
2982/*
2983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2984% %
2985% %
2986% %
2987+ 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 %
2988% %
2989% %
2990% %
2991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2992%
2993% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2994% pixel cache as defined by the geometry parameters. A pointer to the pixels
2995% is returned if the pixels are transferred, otherwise a NULL is returned.
2996%
2997% The format of the GetVirtualPixelsFromNexus() method is:
2998%
2999% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3000% const VirtualPixelMethod method,const long x,const long y,
3001% const unsigned long columns,const unsigned long rows,
3002% NexusInfo *nexus_info,ExceptionInfo *exception)
3003%
3004% A description of each parameter follows:
3005%
3006% o image: the image.
3007%
3008% o virtual_pixel_method: the virtual pixel method.
3009%
3010% o x,y,columns,rows: These values define the perimeter of a region of
3011% pixels.
3012%
3013% o nexus_info: the cache nexus to acquire.
3014%
3015% o exception: return any errors or warnings in this structure.
3016%
3017*/
3018
3019static long
3020 DitherMatrix[64] =
3021 {
3022 0, 48, 12, 60, 3, 51, 15, 63,
3023 32, 16, 44, 28, 35, 19, 47, 31,
3024 8, 56, 4, 52, 11, 59, 7, 55,
3025 40, 24, 36, 20, 43, 27, 39, 23,
3026 2, 50, 14, 62, 1, 49, 13, 61,
3027 34, 18, 46, 30, 33, 17, 45, 29,
3028 10, 58, 6, 54, 9, 57, 5, 53,
3029 42, 26, 38, 22, 41, 25, 37, 21
3030 };
3031
3032static inline long DitherX(const unsigned long columns,const long x)
3033{
3034 long
3035 index;
3036
3037 index=x+DitherMatrix[x & 0x07]-32L;
3038 if (index < 0L)
3039 return(0L);
3040 if (index >= (long) columns)
3041 return((long) columns-1L);
3042 return(index);
3043}
3044
3045static inline long DitherY(const unsigned long rows,const long y)
3046{
3047 long
3048 index;
3049
3050 index=y+DitherMatrix[y & 0x07]-32L;
3051 if (index < 0L)
3052 return(0L);
3053 if (index >= (long) rows)
3054 return((long) rows-1L);
3055 return(index);
3056}
3057
3058static inline long EdgeX(const unsigned long columns,const long x)
3059{
3060 if (x < 0L)
3061 return(0L);
3062 if (x >= (long) columns)
3063 return((long) columns-1L);
3064 return(x);
3065}
3066
3067static inline long EdgeY(const unsigned long rows,const long y)
3068{
3069 if (y < 0L)
3070 return(0L);
3071 if (y >= (long) rows)
3072 return((long) rows-1L);
3073 return(y);
3074}
3075
3076static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
3077{
3078 return((long) (columns*GetPseudoRandomValue(random_info)));
3079}
3080
3081static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
3082{
3083 return((long) (rows*GetPseudoRandomValue(random_info)));
3084}
3085
3086/*
3087 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3088 returns not only the quotient (tile the offset falls in) but also the positive
3089 remainer within that tile such that 0 <= remainder < extent. This method is
3090 essentially a ldiv() using a floored modulo division rather than the normal
3091 default truncated modulo division.
3092*/
3093static inline MagickModulo VirtualPixelModulo(const long offset,
3094 const unsigned long extent)
3095{
3096 MagickModulo
3097 modulo;
3098
3099 modulo.quotient=offset/(long) extent;
3100 if (offset < 0L)
3101 modulo.quotient--;
3102 modulo.remainder=offset-modulo.quotient*(long) extent;
3103 return(modulo);
3104}
3105
3106MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3107 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3108 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3109 ExceptionInfo *exception)
3110{
3111 CacheInfo
3112 *cache_info;
3113
3114 MagickOffsetType
3115 offset;
3116
3117 MagickSizeType
3118 length,
3119 number_pixels;
3120
3121 NexusInfo
3122 **virtual_nexus;
3123
3124 PixelPacket
3125 *pixels,
3126 virtual_pixel;
3127
3128 RectangleInfo
3129 region;
3130
3131 register const IndexPacket
3132 *__restrict nexus_indexes;
3133
3134 register const PixelPacket
3135 *__restrict p;
3136
3137 register IndexPacket
3138 *__restrict indexes;
3139
3140 register long
3141 u,
3142 v;
3143
3144 register PixelPacket
3145 *__restrict q;
3146
3147 /*
3148 Acquire pixels.
3149 */
3150 if (image->debug != MagickFalse)
3151 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3152 cache_info=(CacheInfo *) image->cache;
3153 if (cache_info->type == UndefinedCache)
3154 return((const PixelPacket *) NULL);
3155 region.x=x;
3156 region.y=y;
3157 region.width=columns;
3158 region.height=rows;
3159 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3160 if (pixels == (PixelPacket *) NULL)
3161 return((const PixelPacket *) NULL);
3162 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
3163 length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
3164 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3165 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3166 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3167 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3168 {
3169 MagickBooleanType
3170 status;
3171
3172 /*
3173 Pixel request is inside cache extents.
3174 */
3175 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3176 return(pixels);
3177 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3178 if (status == MagickFalse)
3179 return((const PixelPacket *) NULL);
3180 if ((cache_info->storage_class == PseudoClass) ||
3181 (cache_info->colorspace == CMYKColorspace))
3182 {
3183 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3184 if (status == MagickFalse)
3185 return((const PixelPacket *) NULL);
3186 }
3187 return(pixels);
3188 }
3189 /*
3190 Pixel request is outside cache extents.
3191 */
3192 q=pixels;
3193 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3194 virtual_nexus=AcquirePixelCacheNexus(1);
3195 if (virtual_nexus == (NexusInfo **) NULL)
3196 {
3197 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3198 "UnableToGetCacheNexus","`%s'",image->filename);
3199 return((const PixelPacket *) NULL);
3200 }
3201 switch (virtual_pixel_method)
3202 {
3203 case BlackVirtualPixelMethod:
3204 {
3205 virtual_pixel.red=0;
3206 virtual_pixel.green=0;
3207 virtual_pixel.blue=0;
3208 virtual_pixel.opacity=OpaqueOpacity;
3209 break;
3210 }
3211 case GrayVirtualPixelMethod:
3212 {
3213 virtual_pixel.red=(Quantum) QuantumRange/2;
3214 virtual_pixel.green=(Quantum) QuantumRange/2;
3215 virtual_pixel.blue=(Quantum) QuantumRange/2;
3216 virtual_pixel.opacity=(Quantum) OpaqueOpacity;
3217 break;
3218 }
3219 case TransparentVirtualPixelMethod:
3220 {
3221 virtual_pixel.red=(Quantum) 0;
3222 virtual_pixel.green=(Quantum) 0;
3223 virtual_pixel.blue=(Quantum) 0;
3224 virtual_pixel.opacity=(Quantum) TransparentOpacity;
3225 break;
3226 }
3227 case MaskVirtualPixelMethod:
3228 case WhiteVirtualPixelMethod:
3229 {
3230 virtual_pixel.red=(Quantum) QuantumRange;
3231 virtual_pixel.green=(Quantum) QuantumRange;
3232 virtual_pixel.blue=(Quantum) QuantumRange;
3233 virtual_pixel.opacity=OpaqueOpacity;
3234 break;
3235 }
3236 default:
3237 {
3238 virtual_pixel=image->background_color;
3239 break;
3240 }
3241 }
3242 for (v=0; v < (long) rows; v++)
3243 {
3244 for (u=0; u < (long) columns; u+=length)
3245 {
3246 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3247 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3248 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3249 {
3250 MagickModulo
3251 x_modulo,
3252 y_modulo;
3253
3254 /*
3255 Transfer a single pixel.
3256 */
3257 length=(MagickSizeType) 1;
3258 switch (virtual_pixel_method)
3259 {
3260 case BackgroundVirtualPixelMethod:
3261 case ConstantVirtualPixelMethod:
3262 case BlackVirtualPixelMethod:
3263 case GrayVirtualPixelMethod:
3264 case TransparentVirtualPixelMethod:
3265 case MaskVirtualPixelMethod:
3266 case WhiteVirtualPixelMethod:
3267 {
3268 p=(&virtual_pixel);
3269 break;
3270 }
3271 case EdgeVirtualPixelMethod:
3272 default:
3273 {
3274 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3275 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
3276 1UL,1UL,virtual_nexus[0],exception);
3277 break;
3278 }
3279 case RandomVirtualPixelMethod:
3280 {
3281 if (cache_info->random_info == (RandomInfo *) NULL)
3282 cache_info->random_info=AcquireRandomInfo();
3283 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3284 RandomX(cache_info->columns,cache_info->random_info),
3285 RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
3286 virtual_nexus[0],exception);
3287 break;
3288 }
3289 case DitherVirtualPixelMethod:
3290 {
3291 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3292 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
3293 1UL,1UL,virtual_nexus[0],exception);
3294 break;
3295 }
3296 case TileVirtualPixelMethod:
3297 {
3298 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3299 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3300 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3301 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3302 exception);
3303 break;
3304 }
3305 case MirrorVirtualPixelMethod:
3306 {
3307 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3308 if ((x_modulo.quotient & 0x01) == 1L)
3309 x_modulo.remainder=(long) cache_info->columns-
3310 x_modulo.remainder-1L;
3311 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3312 if ((y_modulo.quotient & 0x01) == 1L)
3313 y_modulo.remainder=(long) cache_info->rows-
3314 y_modulo.remainder-1L;
3315 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3316 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3317 exception);
3318 break;
3319 }
3320 case CheckerTileVirtualPixelMethod:
3321 {
3322 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3323 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3324 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3325 {
3326 p=(&virtual_pixel);
3327 break;
3328 }
3329 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3330 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3331 exception);
3332 break;
3333 }
3334 case HorizontalTileVirtualPixelMethod:
3335 {
3336 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3337 {
3338 p=(&virtual_pixel);
3339 break;
3340 }
3341 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3342 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3343 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3344 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3345 exception);
3346 break;
3347 }
3348 case VerticalTileVirtualPixelMethod:
3349 {
3350 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3351 {
3352 p=(&virtual_pixel);
3353 break;
3354 }
3355 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3356 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3357 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3358 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3359 exception);
3360 break;
3361 }
3362 case HorizontalTileEdgeVirtualPixelMethod:
3363 {
3364 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3365 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3366 x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
3367 virtual_nexus[0],exception);
3368 break;
3369 }
3370 case VerticalTileEdgeVirtualPixelMethod:
3371 {
3372 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3373 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3374 EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
3375 virtual_nexus[0],exception);
3376 break;
3377 }
3378 }
3379 if (p == (const PixelPacket *) NULL)
3380 break;
3381 *q++=(*p);
3382 if (indexes != (IndexPacket *) NULL)
3383 {
3384 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3385 virtual_nexus[0]);
3386 if (nexus_indexes != (const IndexPacket *) NULL)
3387 *indexes++=(*nexus_indexes);
3388 }
3389 continue;
3390 }
3391 /*
3392 Transfer a run of pixels.
3393 */
3394 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3395 (unsigned long) length,1UL,virtual_nexus[0],exception);
3396 if (p == (const PixelPacket *) NULL)
3397 break;
3398 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3399 q+=length;
3400 if (indexes != (IndexPacket *) NULL)
3401 {
3402 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3403 if (nexus_indexes != (const IndexPacket *) NULL)
3404 {
3405 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3406 sizeof(*nexus_indexes));
3407 indexes+=length;
3408 }
3409 }
3410 }
3411 }
3412 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3413 return(pixels);
3414}
3415
3416/*
3417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3418% %
3419% %
3420% %
3421+ G e t V i r t u a l P i x e l C a c h e %
3422% %
3423% %
3424% %
3425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3426%
3427% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3428% cache as defined by the geometry parameters. A pointer to the pixels
3429% is returned if the pixels are transferred, otherwise a NULL is returned.
3430%
3431% The format of the GetVirtualPixelCache() method is:
3432%
3433% const PixelPacket *GetVirtualPixelCache(const Image *image,
3434% const VirtualPixelMethod virtual_pixel_method,const long x,
3435% const long y,const unsigned long columns,const unsigned long rows,
3436% ExceptionInfo *exception)
3437%
3438% A description of each parameter follows:
3439%
3440% o image: the image.
3441%
3442% o virtual_pixel_method: the virtual pixel method.
3443%
3444% o x,y,columns,rows: These values define the perimeter of a region of
3445% pixels.
3446%
3447% o exception: return any errors or warnings in this structure.
3448%
3449*/
3450static const PixelPacket *GetVirtualPixelCache(const Image *image,
3451 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3452 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3453{
3454 CacheInfo
3455 *cache_info;
3456
3457 const PixelPacket
3458 *pixels;
3459
3460 long
3461 id;
3462
3463 if (image->debug != MagickFalse)
3464 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3465 cache_info=(CacheInfo *) image->cache;
3466 id=GetOpenMPThreadId();
3467 assert(id < (long) cache_info->number_threads);
3468 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3469 cache_info->nexus_info[id],exception);
3470 return(pixels);
3471}
3472
3473/*
3474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3475% %
3476% %
3477% %
3478% G e t V i r t u a l P i x e l Q u e u e %
3479% %
3480% %
3481% %
3482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3483%
3484% GetVirtualPixelQueue() returns the virtual pixels associated with the
3485% last call to QueueAuthenticPixels() or GetVirtualPixels().
3486%
3487% The format of the GetVirtualPixelQueue() method is:
3488%
3489% const PixelPacket *GetVirtualPixelQueue(const Image image)
3490%
3491% A description of each parameter follows:
3492%
3493% o image: the image.
3494%
3495*/
3496MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3497{
3498 CacheInfo
3499 *cache_info;
3500
3501 assert(image != (const Image *) NULL);
3502 assert(image->signature == MagickSignature);
3503 if (image->debug != MagickFalse)
3504 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3505 assert(image->cache != (Cache) NULL);
3506 cache_info=(CacheInfo *) image->cache;
3507 assert(cache_info->signature == MagickSignature);
3508 if (cache_info->methods.get_virtual_pixels_handler ==
3509 (GetVirtualPixelsHandler) NULL)
3510 return((PixelPacket *) NULL);
3511 return(cache_info->methods.get_virtual_pixels_handler(image));
3512}
3513
3514/*
3515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3516% %
3517% %
3518% %
3519% G e t V i r t u a l P i x e l s %
3520% %
3521% %
3522% %
3523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3524%
3525% GetVirtualPixels() returns an immutable pixel region. If the
3526% region is successfully accessed, a pointer to it is returned, otherwise
3527% NULL is returned. The returned pointer may point to a temporary working
3528% copy of the pixels or it may point to the original pixels in memory.
3529% Performance is maximized if the selected region is part of one row, or one
3530% or more full rows, since there is opportunity to access the pixels in-place
3531% (without a copy) if the image is in RAM, or in a memory-mapped file. The
3532% returned pointer should *never* be deallocated by the user.
3533%
3534% Pixels accessed via the returned pointer represent a simple array of type
3535% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3536% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3537% the black color component or to obtain the colormap indexes (of type
3538% IndexPacket) corresponding to the region.
3539%
3540% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3541%
3542% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3543% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3544% GetCacheViewAuthenticPixels() instead.
3545%
3546% The format of the GetVirtualPixels() method is:
3547%
3548% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3549% const long y,const unsigned long columns,const unsigned long rows,
3550% ExceptionInfo *exception)
3551%
3552% A description of each parameter follows:
3553%
3554% o image: the image.
3555%
3556% o x,y,columns,rows: These values define the perimeter of a region of
3557% pixels.
3558%
3559% o exception: return any errors or warnings in this structure.
3560%
3561*/
3562MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3563 const long x,const long y,const unsigned long columns,
3564 const unsigned long rows,ExceptionInfo *exception)
3565{
3566 CacheInfo
3567 *cache_info;
3568
3569 const PixelPacket
3570 *pixels;
3571
3572 assert(image != (const Image *) NULL);
3573 assert(image->signature == MagickSignature);
3574 if (image->debug != MagickFalse)
3575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3576 assert(image->cache != (Cache) NULL);
3577 cache_info=(CacheInfo *) image->cache;
3578 assert(cache_info->signature == MagickSignature);
3579 if (cache_info->methods.get_virtual_pixel_handler ==
3580 (GetVirtualPixelHandler) NULL)
3581 return((const PixelPacket *) NULL);
3582 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3583 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3584 return(pixels);
3585}
3586
3587/*
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589% %
3590% %
3591% %
3592+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3593% %
3594% %
3595% %
3596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597%
3598% GetVirtualPixelsCache() returns the pixels associated with the last call
3599% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3600%
3601% The format of the GetVirtualPixelsCache() method is:
3602%
3603% PixelPacket *GetVirtualPixelsCache(const Image *image)
3604%
3605% A description of each parameter follows:
3606%
3607% o image: the image.
3608%
3609*/
3610static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3611{
3612 CacheInfo
3613 *cache_info;
3614
3615 const PixelPacket
3616 *pixels;
3617
3618 long
3619 id;
3620
3621 if (image->debug != MagickFalse)
3622 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3623 cache_info=(CacheInfo *) image->cache;
3624 id=GetOpenMPThreadId();
3625 assert(id < (long) cache_info->number_threads);
3626 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3627 return(pixels);
3628}
3629
3630/*
3631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632% %
3633% %
3634% %
3635+ G e t V i r t u a l P i x e l s N e x u s %
3636% %
3637% %
3638% %
3639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3640%
3641% GetVirtualPixelsNexus() returns the pixels associated with the specified
3642% cache nexus.
3643%
3644% The format of the GetVirtualPixelsNexus() method is:
3645%
3646% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3647% NexusInfo *nexus_info)
3648%
3649% A description of each parameter follows:
3650%
3651% o cache: the pixel cache.
3652%
3653% o nexus_info: the cache nexus to return the colormap pixels.
3654%
3655*/
3656MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3657 NexusInfo *nexus_info)
3658{
3659 CacheInfo
3660 *cache_info;
3661
3662 if (cache == (Cache) NULL)
3663 return((PixelPacket *) NULL);
3664 cache_info=(CacheInfo *) cache;
3665 assert(cache_info->signature == MagickSignature);
3666 if (cache_info->storage_class == UndefinedClass)
3667 return((PixelPacket *) NULL);
3668 return((const PixelPacket *) nexus_info->pixels);
3669}
3670
3671/*
3672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3673% %
3674% %
3675% %
3676+ M a s k P i x e l C a c h e N e x u s %
3677% %
3678% %
3679% %
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681%
3682% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3683% The method returns MagickTrue if the pixel region is masked, otherwise
3684% MagickFalse.
3685%
3686% The format of the MaskPixelCacheNexus() method is:
3687%
3688% MagickBooleanType MaskPixelCacheNexus(Image *image,
3689% NexusInfo *nexus_info,ExceptionInfo *exception)
3690%
3691% A description of each parameter follows:
3692%
3693% o image: the image.
3694%
3695% o nexus_info: the cache nexus to clip.
3696%
3697% o exception: return any errors or warnings in this structure.
3698%
3699*/
3700
3701static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3702 const MagickRealType alpha,const MagickPixelPacket *q,
3703 const MagickRealType beta,MagickPixelPacket *composite)
3704{
3705 MagickRealType
3706 gamma;
3707
3708 if (alpha == TransparentOpacity)
3709 {
3710 *composite=(*q);
3711 return;
3712 }
3713 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3714 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3715 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3716 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3717 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3718 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3719 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3720}
3721
3722static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3723 ExceptionInfo *exception)
3724{
3725 CacheInfo
3726 *cache_info;
3727
3728 MagickPixelPacket
3729 alpha,
3730 beta;
3731
3732 MagickSizeType
3733 number_pixels;
3734
3735 NexusInfo
3736 **clip_nexus,
3737 **image_nexus;
3738
3739 register const PixelPacket
3740 *__restrict r;
3741
3742 register IndexPacket
3743 *__restrict nexus_indexes,
3744 *__restrict indexes;
3745
3746 register long
3747 i;
3748
3749 register PixelPacket
3750 *__restrict p,
3751 *__restrict q;
3752
3753 /*
3754 Apply clip mask.
3755 */
3756 if (image->debug != MagickFalse)
3757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3758 if (image->mask == (Image *) NULL)
3759 return(MagickFalse);
3760 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3761 if (cache_info == (Cache) NULL)
3762 return(MagickFalse);
3763 image_nexus=AcquirePixelCacheNexus(1);
3764 clip_nexus=AcquirePixelCacheNexus(1);
3765 if ((image_nexus == (NexusInfo **) NULL) ||
3766 (clip_nexus == (NexusInfo **) NULL))
3767 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3768 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3769 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
3770 exception);
3771 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3772 q=nexus_info->pixels;
3773 nexus_indexes=nexus_info->indexes;
3774 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3775 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3776 nexus_info->region.height,clip_nexus[0],&image->exception);
3777 GetMagickPixelPacket(image,&alpha);
3778 GetMagickPixelPacket(image,&beta);
3779 number_pixels=(MagickSizeType) nexus_info->region.width*
3780 nexus_info->region.height;
3781 for (i=0; i < (long) number_pixels; i++)
3782 {
3783 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3784 break;
3785 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3786 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3787 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3788 &alpha,alpha.opacity,&beta);
3789 q->red=RoundToQuantum(beta.red);
3790 q->green=RoundToQuantum(beta.green);
3791 q->blue=RoundToQuantum(beta.blue);
3792 q->opacity=RoundToQuantum(beta.opacity);
3793 if (cache_info->active_index_channel != MagickFalse)
3794 nexus_indexes[i]=indexes[i];
3795 p++;
3796 q++;
3797 r++;
3798 }
3799 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3800 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3801 if (i < (long) number_pixels)
3802 return(MagickFalse);
3803 return(MagickTrue);
3804}
3805
3806/*
3807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3808% %
3809% %
3810% %
3811+ O p e n P i x e l C a c h e %
3812% %
3813% %
3814% %
3815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3816%
3817% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3818% dimensions, allocating space for the image pixels and optionally the
3819% colormap indexes, and memory mapping the cache if it is disk based. The
3820% cache nexus array is initialized as well.
3821%
3822% The format of the OpenPixelCache() method is:
3823%
3824% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3825% ExceptionInfo *exception)
3826%
3827% A description of each parameter follows:
3828%
3829% o image: the image.
3830%
3831% o mode: ReadMode, WriteMode, or IOMode.
3832%
3833% o exception: return any errors or warnings in this structure.
3834%
3835*/
3836
3837static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
3838{
3839 cache_info->mapped=MagickFalse;
3840 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3841 cache_info->length);
3842 if (cache_info->pixels == (PixelPacket *) NULL)
3843 {
3844 cache_info->mapped=MagickTrue;
3845 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3846 cache_info->length);
3847 }
3848}
3849
3850static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3851{
3852 CacheInfo
3853 *cache_info;
3854
3855 MagickOffsetType
3856 count,
3857 extent,
3858 offset;
3859
3860 cache_info=(CacheInfo *) image->cache;
3861 if (image->debug != MagickFalse)
3862 {
3863 char
3864 format[MaxTextExtent],
3865 message[MaxTextExtent];
3866
3867 (void) FormatMagickSize(length,format);
3868 (void) FormatMagickString(message,MaxTextExtent,
3869 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3870 cache_info->cache_filename,cache_info->file,format);
3871 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3872 }
3873 if (length != (MagickSizeType) ((MagickOffsetType) length))
3874 return(MagickFalse);
3875 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3876 if (extent < 0)
3877 return(MagickFalse);
3878 if ((MagickSizeType) extent >= length)
3879 return(MagickTrue);
3880 offset=(MagickOffsetType) length-1;
3881 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3882 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3883}
3884
3885static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3886 ExceptionInfo *exception)
3887{
3888 char
3889 format[MaxTextExtent],
3890 message[MaxTextExtent];
3891
3892 CacheInfo
3893 *cache_info,
3894 source_info;
3895
3896 MagickSizeType
3897 length,
3898 number_pixels;
3899
3900 MagickStatusType
3901 status;
3902
3903 size_t
3904 packet_size;
3905
3906 unsigned long
3907 columns;
3908
3909 if (image->debug != MagickFalse)
3910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3911 if ((image->columns == 0) || (image->rows == 0))
3912 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3913 cache_info=(CacheInfo *) image->cache;
3914 source_info=(*cache_info);
3915 source_info.file=(-1);
3916 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
3917 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003918 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003919 cache_info->rows=image->rows;
3920 cache_info->columns=image->columns;
3921 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3922 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3923 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3924 packet_size=sizeof(PixelPacket);
3925 if (cache_info->active_index_channel != MagickFalse)
3926 packet_size+=sizeof(IndexPacket);
3927 length=number_pixels*packet_size;
3928 columns=(unsigned long) (length/cache_info->rows/packet_size);
3929 if (cache_info->columns != columns)
3930 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3931 image->filename);
3932 cache_info->length=length;
3933 status=AcquireMagickResource(AreaResource,cache_info->length);
3934 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3935 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3936 {
3937 status=AcquireMagickResource(MemoryResource,cache_info->length);
3938 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3939 (cache_info->type == MemoryCache))
3940 {
3941 AcquirePixelCachePixels(cache_info);
3942 if (cache_info->pixels == (PixelPacket *) NULL)
3943 cache_info->pixels=source_info.pixels;
3944 else
3945 {
3946 /*
3947 Create memory pixel cache.
3948 */
3949 if (image->debug != MagickFalse)
3950 {
3951 (void) FormatMagickSize(cache_info->length,format);
3952 (void) FormatMagickString(message,MaxTextExtent,
3953 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
3954 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
3955 cache_info->columns,cache_info->rows,format);
3956 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3957 message);
3958 }
3959 cache_info->storage_class=image->storage_class;
3960 cache_info->colorspace=image->colorspace;
3961 cache_info->type=MemoryCache;
3962 cache_info->indexes=(IndexPacket *) NULL;
3963 if (cache_info->active_index_channel != MagickFalse)
3964 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3965 number_pixels);
3966 if (source_info.storage_class != UndefinedClass)
3967 {
3968 status|=ClonePixelCachePixels(cache_info,&source_info,
3969 exception);
3970 RelinquishPixelCachePixels(&source_info);
3971 }
3972 return(MagickTrue);
3973 }
3974 }
3975 RelinquishMagickResource(MemoryResource,cache_info->length);
3976 }
3977 /*
3978 Create pixel cache on disk.
3979 */
3980 status=AcquireMagickResource(DiskResource,cache_info->length);
3981 if (status == MagickFalse)
3982 {
3983 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3984 "CacheResourcesExhausted","`%s'",image->filename);
3985 return(MagickFalse);
3986 }
3987 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3988 {
3989 RelinquishMagickResource(DiskResource,cache_info->length);
3990 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3991 image->filename);
3992 return(MagickFalse);
3993 }
3994 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3995 cache_info->length);
3996 if (status == MagickFalse)
3997 {
3998 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3999 image->filename);
4000 return(MagickFalse);
4001 }
4002 cache_info->storage_class=image->storage_class;
4003 cache_info->colorspace=image->colorspace;
4004 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4005 status=AcquireMagickResource(AreaResource,cache_info->length);
4006 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4007 cache_info->type=DiskCache;
4008 else
4009 {
4010 status=AcquireMagickResource(MapResource,cache_info->length);
4011 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4012 (cache_info->type != MemoryCache))
4013 cache_info->type=DiskCache;
4014 else
4015 {
4016 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4017 cache_info->offset,(size_t) cache_info->length);
4018 if (cache_info->pixels == (PixelPacket *) NULL)
4019 {
4020 cache_info->pixels=source_info.pixels;
4021 cache_info->type=DiskCache;
4022 }
4023 else
4024 {
4025 /*
4026 Create file-backed memory-mapped pixel cache.
4027 */
4028 (void) ClosePixelCacheOnDisk(cache_info);
4029 cache_info->type=MapCache;
4030 cache_info->mapped=MagickTrue;
4031 cache_info->indexes=(IndexPacket *) NULL;
4032 if (cache_info->active_index_channel != MagickFalse)
4033 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4034 number_pixels);
4035 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4036 {
4037 status=ClonePixelCachePixels(cache_info,&source_info,
4038 exception);
4039 RelinquishPixelCachePixels(&source_info);
4040 }
4041 if (image->debug != MagickFalse)
4042 {
4043 (void) FormatMagickSize(cache_info->length,format);
4044 (void) FormatMagickString(message,MaxTextExtent,
4045 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4046 cache_info->filename,cache_info->cache_filename,
4047 cache_info->file,cache_info->columns,cache_info->rows,
4048 format);
4049 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4050 message);
4051 }
4052 return(MagickTrue);
4053 }
4054 }
4055 RelinquishMagickResource(MapResource,cache_info->length);
4056 }
4057 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4058 {
4059 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4060 RelinquishPixelCachePixels(&source_info);
4061 }
4062 if (image->debug != MagickFalse)
4063 {
4064 (void) FormatMagickSize(cache_info->length,format);
4065 (void) FormatMagickString(message,MaxTextExtent,
4066 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4067 cache_info->cache_filename,cache_info->file,cache_info->columns,
4068 cache_info->rows,format);
4069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4070 }
4071 return(MagickTrue);
4072}
4073
4074/*
4075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4076% %
4077% %
4078% %
4079+ P e r s i s t P i x e l C a c h e %
4080% %
4081% %
4082% %
4083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4084%
4085% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4086% persistent pixel cache is one that resides on disk and is not destroyed
4087% when the program exits.
4088%
4089% The format of the PersistPixelCache() method is:
4090%
4091% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4092% const MagickBooleanType attach,MagickOffsetType *offset,
4093% ExceptionInfo *exception)
4094%
4095% A description of each parameter follows:
4096%
4097% o image: the image.
4098%
4099% o filename: the persistent pixel cache filename.
4100%
4101% o initialize: A value other than zero initializes the persistent pixel
4102% cache.
4103%
4104% o offset: the offset in the persistent cache to store pixels.
4105%
4106% o exception: return any errors or warnings in this structure.
4107%
4108*/
4109MagickExport MagickBooleanType PersistPixelCache(Image *image,
4110 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4111 ExceptionInfo *exception)
4112{
4113 CacheInfo
4114 *cache_info,
4115 *clone_info;
4116
4117 Image
4118 clone_image;
4119
4120 long
4121 pagesize;
4122
4123 MagickBooleanType
4124 status;
4125
4126 assert(image != (Image *) NULL);
4127 assert(image->signature == MagickSignature);
4128 if (image->debug != MagickFalse)
4129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4130 assert(image->cache != (void *) NULL);
4131 assert(filename != (const char *) NULL);
4132 assert(offset != (MagickOffsetType *) NULL);
4133 pagesize=(-1);
4134#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGESIZE)
4135 pagesize=sysconf(_SC_PAGESIZE);
4136#elif defined(MAGICKCORE_HAVE_GETPAGESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
4137 pagesize=getpagesize();
4138#endif
4139 if (pagesize <= 0)
4140 pagesize=4096;
4141 cache_info=(CacheInfo *) image->cache;
4142 assert(cache_info->signature == MagickSignature);
4143 if (attach != MagickFalse)
4144 {
4145 /*
4146 Attach persistent pixel cache.
4147 */
4148 if (image->debug != MagickFalse)
4149 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4150 "attach persistent cache");
4151 (void) CopyMagickString(cache_info->cache_filename,filename,
4152 MaxTextExtent);
4153 cache_info->type=DiskCache;
4154 cache_info->offset=(*offset);
4155 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4156 return(MagickFalse);
4157 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4158 *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
4159 return(MagickTrue);
4160 }
4161 if ((cache_info->type != MemoryCache) && (cache_info->reference_count == 1))
4162 {
4163 (void) LockSemaphoreInfo(cache_info->semaphore);
4164 if ((cache_info->type != MemoryCache) &&
4165 (cache_info->reference_count == 1))
4166 {
4167 int
4168 status;
4169
4170 /*
4171 Usurp resident persistent pixel cache.
4172 */
4173 status=rename(cache_info->cache_filename,filename);
4174 if (status == 0)
4175 {
4176 (void) CopyMagickString(cache_info->cache_filename,filename,
4177 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00004178 *offset+=cache_info->length+pagesize-(cache_info->length %
4179 pagesize);
cristy87528ea2009-09-10 14:53:56 +00004180 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4181 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004182 if (image->debug != MagickFalse)
4183 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4184 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004185 return(MagickTrue);
4186 }
4187 }
4188 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4189 }
4190 /*
4191 Attach persistent pixel cache.
4192 */
4193 clone_image=(*image);
4194 clone_info=(CacheInfo *) clone_image.cache;
4195 image->cache=ClonePixelCache(cache_info);
4196 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4197 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4198 cache_info->type=DiskCache;
4199 cache_info->offset=(*offset);
4200 cache_info=(CacheInfo *) image->cache;
4201 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4202 if (status != MagickFalse)
4203 {
4204 status=OpenPixelCache(image,IOMode,exception);
4205 if (status != MagickFalse)
4206 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4207 }
4208 *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
4209 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4210 return(status);
4211}
4212
4213/*
4214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4215% %
4216% %
4217% %
4218+ Q u e u e A u t h e n t i c N e x u s %
4219% %
4220% %
4221% %
4222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223%
4224% QueueAuthenticNexus() allocates an region to store image pixels as defined
4225% by the region rectangle and returns a pointer to the region. This region is
4226% subsequently transferred from the pixel cache with
4227% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4228% pixels are transferred, otherwise a NULL is returned.
4229%
4230% The format of the QueueAuthenticNexus() method is:
4231%
4232% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4233% const unsigned long columns,const unsigned long rows,
4234% NexusInfo *nexus_info,ExceptionInfo *exception)
4235%
4236% A description of each parameter follows:
4237%
4238% o image: the image.
4239%
4240% o x,y,columns,rows: These values define the perimeter of a region of
4241% pixels.
4242%
4243% o nexus_info: the cache nexus to set.
4244%
4245% o exception: return any errors or warnings in this structure.
4246%
4247*/
4248MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4249 const long y,const unsigned long columns,const unsigned long rows,
4250 NexusInfo *nexus_info,ExceptionInfo *exception)
4251{
4252 CacheInfo
4253 *cache_info;
4254
4255 MagickOffsetType
4256 offset;
4257
4258 MagickSizeType
4259 number_pixels;
4260
4261 RectangleInfo
4262 region;
4263
4264 /*
4265 Validate pixel cache geometry.
4266 */
4267 cache_info=(CacheInfo *) image->cache;
4268 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4269 {
4270 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4271 "NoPixelsDefinedInCache","`%s'",image->filename);
4272 return((PixelPacket *) NULL);
4273 }
4274 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4275 (y >= (long) cache_info->rows))
4276 {
4277 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4278 "PixelsAreNotAuthentic","`%s'",image->filename);
4279 return((PixelPacket *) NULL);
4280 }
4281 offset=(MagickOffsetType) y*cache_info->columns+x;
4282 if (offset < 0)
4283 return((PixelPacket *) NULL);
4284 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4285 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4286 if ((MagickSizeType) offset >= number_pixels)
4287 return((PixelPacket *) NULL);
4288 /*
4289 Return pixel cache.
4290 */
4291 region.x=x;
4292 region.y=y;
4293 region.width=columns;
4294 region.height=rows;
4295 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4296}
4297
4298/*
4299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4300% %
4301% %
4302% %
4303+ 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 %
4304% %
4305% %
4306% %
4307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4308%
4309% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4310% defined by the region rectangle and returns a pointer to the region. This
4311% region is subsequently transferred from the pixel cache with
4312% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4313% pixels are transferred, otherwise a NULL is returned.
4314%
4315% The format of the QueueAuthenticPixelsCache() method is:
4316%
4317% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4318% const long y,const unsigned long columns,const unsigned long rows,
4319% ExceptionInfo *exception)
4320%
4321% A description of each parameter follows:
4322%
4323% o image: the image.
4324%
4325% o x,y,columns,rows: These values define the perimeter of a region of
4326% pixels.
4327%
4328% o exception: return any errors or warnings in this structure.
4329%
4330*/
4331static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4332 const long y,const unsigned long columns,const unsigned long rows,
4333 ExceptionInfo *exception)
4334{
4335 CacheInfo
4336 *cache_info;
4337
4338 long
4339 id;
4340
4341 PixelPacket
4342 *pixels;
4343
4344 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4345 if (cache_info == (Cache) NULL)
4346 return((PixelPacket *) NULL);
4347 id=GetOpenMPThreadId();
4348 assert(id < (long) cache_info->number_threads);
4349 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4350 exception);
4351 return(pixels);
4352}
4353
4354/*
4355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4356% %
4357% %
4358% %
4359% Q u e u e A u t h e n t i c P i x e l s %
4360% %
4361% %
4362% %
4363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4364%
4365% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4366% successfully intialized a pointer to a PixelPacket array representing the
4367% region is returned, otherwise NULL is returned. The returned pointer may
4368% point to a temporary working buffer for the pixels or it may point to the
4369% final location of the pixels in memory.
4370%
4371% Write-only access means that any existing pixel values corresponding to
4372% the region are ignored. This is useful if the initial image is being
4373% created from scratch, or if the existing pixel values are to be
4374% completely replaced without need to refer to their pre-existing values.
4375% The application is free to read and write the pixel buffer returned by
4376% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4377% initialize the pixel array values. Initializing pixel array values is the
4378% application's responsibility.
4379%
4380% Performance is maximized if the selected region is part of one row, or
4381% one or more full rows, since then there is opportunity to access the
4382% pixels in-place (without a copy) if the image is in RAM, or in a
4383% memory-mapped file. The returned pointer should *never* be deallocated
4384% by the user.
4385%
4386% Pixels accessed via the returned pointer represent a simple array of type
4387% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4388% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4389% the black color component or the colormap indexes (of type IndexPacket)
4390% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4391% array has been updated, the changes must be saved back to the underlying
4392% image using SyncAuthenticPixels() or they may be lost.
4393%
4394% The format of the QueueAuthenticPixels() method is:
4395%
4396% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4397% const unsigned long columns,const unsigned long rows,
4398% ExceptionInfo *exception)
4399%
4400% A description of each parameter follows:
4401%
4402% o image: the image.
4403%
4404% o x,y,columns,rows: These values define the perimeter of a region of
4405% pixels.
4406%
4407% o exception: return any errors or warnings in this structure.
4408%
4409*/
4410MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4411 const long y,const unsigned long columns,const unsigned long rows,
4412 ExceptionInfo *exception)
4413{
4414 CacheInfo
4415 *cache_info;
4416
4417 PixelPacket
4418 *pixels;
4419
4420 assert(image != (Image *) NULL);
4421 assert(image->signature == MagickSignature);
4422 if (image->debug != MagickFalse)
4423 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4424 assert(image->cache != (Cache) NULL);
4425 cache_info=(CacheInfo *) image->cache;
4426 assert(cache_info->signature == MagickSignature);
4427 if (cache_info->methods.queue_authentic_pixels_handler ==
4428 (QueueAuthenticPixelsHandler) NULL)
4429 return((PixelPacket *) NULL);
4430 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4431 rows,exception);
4432 return(pixels);
4433}
4434
4435/*
4436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4437% %
4438% %
4439% %
4440+ R e a d P i x e l C a c h e I n d e x e s %
4441% %
4442% %
4443% %
4444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4445%
4446% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4447% the pixel cache.
4448%
4449% The format of the ReadPixelCacheIndexes() method is:
4450%
4451% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4452% NexusInfo *nexus_info,ExceptionInfo *exception)
4453%
4454% A description of each parameter follows:
4455%
4456% o cache_info: the pixel cache.
4457%
4458% o nexus_info: the cache nexus to read the colormap indexes.
4459%
4460% o exception: return any errors or warnings in this structure.
4461%
4462*/
4463static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4464 NexusInfo *nexus_info,ExceptionInfo *exception)
4465{
4466 MagickOffsetType
4467 count,
4468 offset;
4469
4470 MagickSizeType
4471 length,
4472 number_pixels;
4473
4474 register IndexPacket
4475 *__restrict q;
4476
4477 register long
4478 y;
4479
4480 unsigned long
4481 rows;
4482
4483 if (cache_info->debug != MagickFalse)
4484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4485 cache_info->filename);
4486 if (cache_info->active_index_channel == MagickFalse)
4487 return(MagickFalse);
4488 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4489 return(MagickTrue);
4490 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4491 nexus_info->region.x;
4492 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4493 rows=nexus_info->region.height;
4494 number_pixels=length*rows;
4495 if ((cache_info->columns == nexus_info->region.width) &&
4496 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4497 {
4498 length=number_pixels;
4499 rows=1UL;
4500 }
4501 q=nexus_info->indexes;
4502 switch (cache_info->type)
4503 {
4504 case MemoryCache:
4505 case MapCache:
4506 {
4507 register IndexPacket
4508 *__restrict p;
4509
4510 /*
4511 Read indexes from memory.
4512 */
4513 p=cache_info->indexes+offset;
4514 for (y=0; y < (long) rows; y++)
4515 {
4516 (void) CopyMagickMemory(q,p,(size_t) length);
4517 p+=cache_info->columns;
4518 q+=nexus_info->region.width;
4519 }
4520 break;
4521 }
4522 case DiskCache:
4523 {
4524 /*
4525 Read indexes from disk.
4526 */
4527 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4528 {
4529 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4530 cache_info->cache_filename);
4531 return(MagickFalse);
4532 }
4533 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4534 for (y=0; y < (long) rows; y++)
4535 {
4536 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4537 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4538 if ((MagickSizeType) count < length)
4539 break;
4540 offset+=cache_info->columns;
4541 q+=nexus_info->region.width;
4542 }
4543 if (y < (long) rows)
4544 {
4545 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4546 cache_info->cache_filename);
4547 return(MagickFalse);
4548 }
4549 break;
4550 }
4551 default:
4552 break;
4553 }
4554 if ((cache_info->debug != MagickFalse) &&
4555 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4556 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4557 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4558 nexus_info->region.x,nexus_info->region.y);
4559 return(MagickTrue);
4560}
4561
4562/*
4563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4564% %
4565% %
4566% %
4567+ R e a d P i x e l C a c h e P i x e l s %
4568% %
4569% %
4570% %
4571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4572%
4573% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4574% cache.
4575%
4576% The format of the ReadPixelCachePixels() method is:
4577%
4578% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4579% NexusInfo *nexus_info,ExceptionInfo *exception)
4580%
4581% A description of each parameter follows:
4582%
4583% o cache_info: the pixel cache.
4584%
4585% o nexus_info: the cache nexus to read the pixels.
4586%
4587% o exception: return any errors or warnings in this structure.
4588%
4589*/
4590static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4591 NexusInfo *nexus_info,ExceptionInfo *exception)
4592{
4593 MagickOffsetType
4594 count,
4595 offset;
4596
4597 MagickSizeType
4598 length,
4599 number_pixels;
4600
4601 register long
4602 y;
4603
4604 register PixelPacket
4605 *__restrict q;
4606
4607 unsigned long
4608 rows;
4609
4610 if (cache_info->debug != MagickFalse)
4611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4612 cache_info->filename);
4613 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4614 return(MagickTrue);
4615 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4616 nexus_info->region.x;
4617 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4618 rows=nexus_info->region.height;
4619 number_pixels=length*rows;
4620 if ((cache_info->columns == nexus_info->region.width) &&
4621 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4622 {
4623 length=number_pixels;
4624 rows=1UL;
4625 }
4626 q=nexus_info->pixels;
4627 switch (cache_info->type)
4628 {
4629 case MemoryCache:
4630 case MapCache:
4631 {
4632 register PixelPacket
4633 *__restrict p;
4634
4635 /*
4636 Read pixels from memory.
4637 */
4638 p=cache_info->pixels+offset;
4639 for (y=0; y < (long) rows; y++)
4640 {
4641 (void) CopyMagickMemory(q,p,(size_t) length);
4642 p+=cache_info->columns;
4643 q+=nexus_info->region.width;
4644 }
4645 break;
4646 }
4647 case DiskCache:
4648 {
4649 /*
4650 Read pixels from disk.
4651 */
4652 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4653 {
4654 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4655 cache_info->cache_filename);
4656 return(MagickFalse);
4657 }
4658 for (y=0; y < (long) rows; y++)
4659 {
4660 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4661 sizeof(*q),length,(unsigned char *) q);
4662 if ((MagickSizeType) count < length)
4663 break;
4664 offset+=cache_info->columns;
4665 q+=nexus_info->region.width;
4666 }
4667 if (y < (long) rows)
4668 {
4669 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4670 cache_info->cache_filename);
4671 return(MagickFalse);
4672 }
4673 break;
4674 }
4675 default:
4676 break;
4677 }
4678 if ((cache_info->debug != MagickFalse) &&
4679 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4680 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4681 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4682 nexus_info->region.x,nexus_info->region.y);
4683 return(MagickTrue);
4684}
4685
4686/*
4687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4688% %
4689% %
4690% %
4691+ R e f e r e n c e P i x e l C a c h e %
4692% %
4693% %
4694% %
4695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4696%
4697% ReferencePixelCache() increments the reference count associated with the
4698% pixel cache returning a pointer to the cache.
4699%
4700% The format of the ReferencePixelCache method is:
4701%
4702% Cache ReferencePixelCache(Cache cache_info)
4703%
4704% A description of each parameter follows:
4705%
4706% o cache_info: the pixel cache.
4707%
4708*/
4709MagickExport Cache ReferencePixelCache(Cache cache)
4710{
4711 CacheInfo
4712 *cache_info;
4713
4714 assert(cache != (Cache *) NULL);
4715 cache_info=(CacheInfo *) cache;
4716 assert(cache_info->signature == MagickSignature);
4717 if (cache_info->debug != MagickFalse)
4718 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4719 cache_info->filename);
4720 (void) LockSemaphoreInfo(cache_info->semaphore);
4721 cache_info->reference_count++;
4722 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4723 return(cache_info);
4724}
4725
4726/*
4727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728% %
4729% %
4730% %
4731+ S e t P i x e l C a c h e M e t h o d s %
4732% %
4733% %
4734% %
4735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4736%
4737% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4738%
4739% The format of the SetPixelCacheMethods() method is:
4740%
4741% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4742%
4743% A description of each parameter follows:
4744%
4745% o cache: the pixel cache.
4746%
4747% o cache_methods: Specifies a pointer to a CacheMethods structure.
4748%
4749*/
4750MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4751{
4752 CacheInfo
4753 *cache_info;
4754
4755 GetOneAuthenticPixelFromHandler
4756 get_one_authentic_pixel_from_handler;
4757
4758 GetOneVirtualPixelFromHandler
4759 get_one_virtual_pixel_from_handler;
4760
4761 /*
4762 Set cache pixel methods.
4763 */
4764 assert(cache != (Cache) NULL);
4765 assert(cache_methods != (CacheMethods *) NULL);
4766 cache_info=(CacheInfo *) cache;
4767 assert(cache_info->signature == MagickSignature);
4768 if (cache_info->debug != MagickFalse)
4769 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4770 cache_info->filename);
4771 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4772 cache_info->methods.get_virtual_pixel_handler=
4773 cache_methods->get_virtual_pixel_handler;
4774 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4775 cache_info->methods.destroy_pixel_handler=
4776 cache_methods->destroy_pixel_handler;
4777 if (cache_methods->get_virtual_indexes_from_handler !=
4778 (GetVirtualIndexesFromHandler) NULL)
4779 cache_info->methods.get_virtual_indexes_from_handler=
4780 cache_methods->get_virtual_indexes_from_handler;
4781 if (cache_methods->get_authentic_pixels_handler !=
4782 (GetAuthenticPixelsHandler) NULL)
4783 cache_info->methods.get_authentic_pixels_handler=
4784 cache_methods->get_authentic_pixels_handler;
4785 if (cache_methods->queue_authentic_pixels_handler !=
4786 (QueueAuthenticPixelsHandler) NULL)
4787 cache_info->methods.queue_authentic_pixels_handler=
4788 cache_methods->queue_authentic_pixels_handler;
4789 if (cache_methods->sync_authentic_pixels_handler !=
4790 (SyncAuthenticPixelsHandler) NULL)
4791 cache_info->methods.sync_authentic_pixels_handler=
4792 cache_methods->sync_authentic_pixels_handler;
4793 if (cache_methods->get_authentic_pixels_from_handler !=
4794 (GetAuthenticPixelsFromHandler) NULL)
4795 cache_info->methods.get_authentic_pixels_from_handler=
4796 cache_methods->get_authentic_pixels_from_handler;
4797 if (cache_methods->get_authentic_indexes_from_handler !=
4798 (GetAuthenticIndexesFromHandler) NULL)
4799 cache_info->methods.get_authentic_indexes_from_handler=
4800 cache_methods->get_authentic_indexes_from_handler;
4801 get_one_virtual_pixel_from_handler=
4802 cache_info->methods.get_one_virtual_pixel_from_handler;
4803 if (get_one_virtual_pixel_from_handler !=
4804 (GetOneVirtualPixelFromHandler) NULL)
4805 cache_info->methods.get_one_virtual_pixel_from_handler=
4806 cache_methods->get_one_virtual_pixel_from_handler;
4807 get_one_authentic_pixel_from_handler=
4808 cache_methods->get_one_authentic_pixel_from_handler;
4809 if (get_one_authentic_pixel_from_handler !=
4810 (GetOneAuthenticPixelFromHandler) NULL)
4811 cache_info->methods.get_one_authentic_pixel_from_handler=
4812 cache_methods->get_one_authentic_pixel_from_handler;
4813}
4814
4815/*
4816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4817% %
4818% %
4819% %
4820+ S e t P i x e l C a c h e N e x u s P i x e l s %
4821% %
4822% %
4823% %
4824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4825%
4826% SetPixelCacheNexusPixels() defines the region of the cache for the
4827% specified cache nexus.
4828%
4829% The format of the SetPixelCacheNexusPixels() method is:
4830%
4831% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4832% const RectangleInfo *region,NexusInfo *nexus_info,
4833% ExceptionInfo *exception)
4834%
4835% A description of each parameter follows:
4836%
4837% o image: the image.
4838%
4839% o region: A pointer to the RectangleInfo structure that defines the
4840% region of this particular cache nexus.
4841%
4842% o nexus_info: the cache nexus to set.
4843%
4844% o exception: return any errors or warnings in this structure.
4845%
4846*/
4847static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4848 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4849{
4850 CacheInfo
4851 *cache_info;
4852
4853 MagickBooleanType
4854 status;
4855
4856 MagickOffsetType
4857 offset;
4858
4859 MagickSizeType
4860 length,
4861 number_pixels;
4862
4863 if (image->debug != MagickFalse)
4864 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4865 cache_info=(CacheInfo *) image->cache;
4866 assert(cache_info->signature == MagickSignature);
4867 if (cache_info->type == UndefinedCache)
4868 return((PixelPacket *) NULL);
4869 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4870 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4871 nexus_info->region.x=region->x;
4872 nexus_info->region.y=region->y;
4873 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
4874 (image->mask == (Image *) NULL))
4875 {
4876 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4877 nexus_info->region.x;
4878 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
4879 nexus_info->region.width-1;
4880 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4881 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
4882 {
4883 long
4884 x,
4885 y;
4886
4887 x=nexus_info->region.x+nexus_info->region.width;
4888 y=nexus_info->region.y+nexus_info->region.height;
4889 if ((nexus_info->region.x >= 0) &&
4890 (x <= (long) cache_info->columns) &&
4891 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
4892 if ((nexus_info->region.height == 1UL) ||
4893 ((nexus_info->region.x == 0) &&
4894 ((nexus_info->region.width % cache_info->columns) == 0)))
4895 {
4896 /*
4897 Pixels are accessed directly from memory.
4898 */
4899 nexus_info->pixels=cache_info->pixels+offset;
4900 nexus_info->indexes=(IndexPacket *) NULL;
4901 if (cache_info->active_index_channel != MagickFalse)
4902 nexus_info->indexes=cache_info->indexes+offset;
4903 return(nexus_info->pixels);
4904 }
4905 }
4906 }
4907 /*
4908 Pixels are stored in a cache region until they are synced to the cache.
4909 */
4910 number_pixels=(MagickSizeType) nexus_info->region.width*
4911 nexus_info->region.height;
4912 length=number_pixels*sizeof(PixelPacket);
4913 if (cache_info->active_index_channel != MagickFalse)
4914 length+=number_pixels*sizeof(IndexPacket);
4915 if (nexus_info->cache == (PixelPacket *) NULL)
4916 {
4917 nexus_info->length=length;
4918 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4919 if (status == MagickFalse)
4920 return((PixelPacket *) NULL);
4921 }
4922 else
4923 if (nexus_info->length != length)
4924 {
4925 RelinquishCacheNexusPixels(nexus_info);
4926 nexus_info->length=length;
4927 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4928 if (status == MagickFalse)
4929 return((PixelPacket *) NULL);
4930 }
4931 nexus_info->pixels=nexus_info->cache;
4932 nexus_info->indexes=(IndexPacket *) NULL;
4933 if (cache_info->active_index_channel != MagickFalse)
4934 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4935 return(nexus_info->pixels);
4936}
4937
4938/*
4939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4940% %
4941% %
4942% %
4943% 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 %
4944% %
4945% %
4946% %
4947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948%
4949% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4950% pixel cache and returns the previous setting. A virtual pixel is any pixel
4951% access that is outside the boundaries of the image cache.
4952%
4953% The format of the SetPixelCacheVirtualMethod() method is:
4954%
4955% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4956% const VirtualPixelMethod virtual_pixel_method)
4957%
4958% A description of each parameter follows:
4959%
4960% o image: the image.
4961%
4962% o virtual_pixel_method: choose the type of virtual pixel.
4963%
4964*/
4965MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4966 const VirtualPixelMethod virtual_pixel_method)
4967{
4968 CacheInfo
4969 *cache_info;
4970
4971 VirtualPixelMethod
4972 method;
4973
4974 assert(image != (Image *) NULL);
4975 assert(image->signature == MagickSignature);
4976 if (image->debug != MagickFalse)
4977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4978 assert(image->cache != (Cache) NULL);
4979 cache_info=(CacheInfo *) image->cache;
4980 assert(cache_info->signature == MagickSignature);
4981 method=cache_info->virtual_pixel_method;
4982 cache_info->virtual_pixel_method=virtual_pixel_method;
4983 return(method);
4984}
4985
4986/*
4987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4988% %
4989% %
4990% %
4991+ 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 %
4992% %
4993% %
4994% %
4995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4996%
4997% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4998% in-memory or disk cache. The method returns MagickTrue if the pixel region
4999% is synced, otherwise MagickFalse.
5000%
5001% The format of the SyncAuthenticPixelCacheNexus() method is:
5002%
5003% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5004% NexusInfo *nexus_info,ExceptionInfo *exception)
5005%
5006% A description of each parameter follows:
5007%
5008% o image: the image.
5009%
5010% o nexus_info: the cache nexus to sync.
5011%
5012% o exception: return any errors or warnings in this structure.
5013%
5014*/
5015MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5016 NexusInfo *nexus_info,ExceptionInfo *exception)
5017{
5018 CacheInfo
5019 *cache_info;
5020
5021 MagickBooleanType
5022 status;
5023
5024 /*
5025 Transfer pixels to the cache.
5026 */
5027 assert(image != (Image *) NULL);
5028 assert(image->signature == MagickSignature);
5029 if (image->debug != MagickFalse)
5030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5031 if (image->cache == (Cache) NULL)
5032 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5033 cache_info=(CacheInfo *) image->cache;
5034 if (cache_info->type == UndefinedCache)
5035 return(MagickFalse);
5036 if ((image->clip_mask != (Image *) NULL) &&
5037 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5038 return(MagickFalse);
5039 if ((image->mask != (Image *) NULL) &&
5040 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5041 return(MagickFalse);
5042 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5043 return(MagickTrue);
5044 assert(cache_info->signature == MagickSignature);
5045 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5046 if ((cache_info->active_index_channel != MagickFalse) &&
5047 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5048 return(MagickFalse);
5049 return(status);
5050}
5051
5052/*
5053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5054% %
5055% %
5056% %
5057+ S y n c A u t h e n t i c P i x e l C a c h e %
5058% %
5059% %
5060% %
5061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5062%
5063% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5064% or disk cache. The method returns MagickTrue if the pixel region is synced,
5065% otherwise MagickFalse.
5066%
5067% The format of the SyncAuthenticPixelsCache() method is:
5068%
5069% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5070% ExceptionInfo *exception)
5071%
5072% A description of each parameter follows:
5073%
5074% o image: the image.
5075%
5076% o exception: return any errors or warnings in this structure.
5077%
5078*/
5079static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5080 ExceptionInfo *exception)
5081{
5082 CacheInfo
5083 *cache_info;
5084
5085 long
5086 id;
5087
5088 MagickBooleanType
5089 status;
5090
5091 cache_info=(CacheInfo *) image->cache;
5092 id=GetOpenMPThreadId();
5093 assert(id < (long) cache_info->number_threads);
5094 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5095 exception);
5096 return(status);
5097}
5098
5099/*
5100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5101% %
5102% %
5103% %
5104% S y n c A u t h e n t i c P i x e l s %
5105% %
5106% %
5107% %
5108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109%
5110% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5111% The method returns MagickTrue if the pixel region is flushed, otherwise
5112% MagickFalse.
5113%
5114% The format of the SyncAuthenticPixels() method is:
5115%
5116% MagickBooleanType SyncAuthenticPixels(Image *image,
5117% ExceptionInfo *exception)
5118%
5119% A description of each parameter follows:
5120%
5121% o image: the image.
5122%
5123% o exception: return any errors or warnings in this structure.
5124%
5125*/
5126MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5127 ExceptionInfo *exception)
5128{
5129 CacheInfo
5130 *cache_info;
5131
5132 assert(image != (Image *) NULL);
5133 assert(image->signature == MagickSignature);
5134 if (image->debug != MagickFalse)
5135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5136 assert(image->cache != (Cache) NULL);
5137 cache_info=(CacheInfo *) image->cache;
5138 assert(cache_info->signature == MagickSignature);
5139 if (cache_info->methods.sync_authentic_pixels_handler ==
5140 (SyncAuthenticPixelsHandler) NULL)
5141 return(MagickFalse);
5142 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5143}
5144
5145/*
5146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5147% %
5148% %
5149% %
5150+ W r i t e P i x e l C a c h e I n d e x e s %
5151% %
5152% %
5153% %
5154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5155%
5156% WritePixelCacheIndexes() writes the colormap indexes to the specified
5157% region of the pixel cache.
5158%
5159% The format of the WritePixelCacheIndexes() method is:
5160%
5161% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5162% NexusInfo *nexus_info,ExceptionInfo *exception)
5163%
5164% A description of each parameter follows:
5165%
5166% o cache_info: the pixel cache.
5167%
5168% o nexus_info: the cache nexus to write the colormap indexes.
5169%
5170% o exception: return any errors or warnings in this structure.
5171%
5172*/
5173static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5174 NexusInfo *nexus_info,ExceptionInfo *exception)
5175{
5176 MagickOffsetType
5177 count,
5178 offset;
5179
5180 MagickSizeType
5181 length,
5182 number_pixels;
5183
5184 register const IndexPacket
5185 *__restrict p;
5186
5187 register long
5188 y;
5189
5190 unsigned long
5191 rows;
5192
5193 if (cache_info->debug != MagickFalse)
5194 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5195 cache_info->filename);
5196 if (cache_info->active_index_channel == MagickFalse)
5197 return(MagickFalse);
5198 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5199 return(MagickTrue);
5200 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5201 nexus_info->region.x;
5202 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5203 rows=nexus_info->region.height;
5204 number_pixels=(MagickSizeType) length*rows;
5205 if ((cache_info->columns == nexus_info->region.width) &&
5206 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5207 {
5208 length=number_pixels;
5209 rows=1UL;
5210 }
5211 p=nexus_info->indexes;
5212 switch (cache_info->type)
5213 {
5214 case MemoryCache:
5215 case MapCache:
5216 {
5217 register IndexPacket
5218 *__restrict q;
5219
5220 /*
5221 Write indexes to memory.
5222 */
5223 q=cache_info->indexes+offset;
5224 for (y=0; y < (long) rows; y++)
5225 {
5226 (void) CopyMagickMemory(q,p,(size_t) length);
5227 p+=nexus_info->region.width;
5228 q+=cache_info->columns;
5229 }
5230 break;
5231 }
5232 case DiskCache:
5233 {
5234 /*
5235 Write indexes to disk.
5236 */
5237 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5238 {
5239 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5240 cache_info->cache_filename);
5241 return(MagickFalse);
5242 }
5243 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5244 for (y=0; y < (long) rows; y++)
5245 {
5246 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5247 sizeof(PixelPacket)+offset*sizeof(*p),length,
5248 (const unsigned char *) p);
5249 if ((MagickSizeType) count < length)
5250 break;
5251 p+=nexus_info->region.width;
5252 offset+=cache_info->columns;
5253 }
5254 if (y < (long) rows)
5255 {
5256 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5257 cache_info->cache_filename);
5258 return(MagickFalse);
5259 }
5260 break;
5261 }
5262 default:
5263 break;
5264 }
5265 if ((cache_info->debug != MagickFalse) &&
5266 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5267 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5268 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5269 nexus_info->region.x,nexus_info->region.y);
5270 return(MagickTrue);
5271}
5272
5273/*
5274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5275% %
5276% %
5277% %
5278+ W r i t e C a c h e P i x e l s %
5279% %
5280% %
5281% %
5282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5283%
5284% WritePixelCachePixels() writes image pixels to the specified region of the
5285% pixel cache.
5286%
5287% The format of the WritePixelCachePixels() method is:
5288%
5289% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5290% NexusInfo *nexus_info,ExceptionInfo *exception)
5291%
5292% A description of each parameter follows:
5293%
5294% o cache_info: the pixel cache.
5295%
5296% o nexus_info: the cache nexus to write the pixels.
5297%
5298% o exception: return any errors or warnings in this structure.
5299%
5300*/
5301static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5302 NexusInfo *nexus_info,ExceptionInfo *exception)
5303{
5304 MagickOffsetType
5305 count,
5306 offset;
5307
5308 MagickSizeType
5309 length,
5310 number_pixels;
5311
5312 register long
5313 y;
5314
5315 register const PixelPacket
5316 *__restrict p;
5317
5318 unsigned long
5319 rows;
5320
5321 if (cache_info->debug != MagickFalse)
5322 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5323 cache_info->filename);
5324 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5325 return(MagickTrue);
5326 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5327 nexus_info->region.x;
5328 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5329 rows=nexus_info->region.height;
5330 number_pixels=length*rows;
5331 if ((cache_info->columns == nexus_info->region.width) &&
5332 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5333 {
5334 length=number_pixels;
5335 rows=1UL;
5336 }
5337 p=nexus_info->pixels;
5338 switch (cache_info->type)
5339 {
5340 case MemoryCache:
5341 case MapCache:
5342 {
5343 register PixelPacket
5344 *__restrict q;
5345
5346 /*
5347 Write pixels to memory.
5348 */
5349 q=cache_info->pixels+offset;
5350 for (y=0; y < (long) rows; y++)
5351 {
5352 (void) CopyMagickMemory(q,p,(size_t) length);
5353 p+=nexus_info->region.width;
5354 q+=cache_info->columns;
5355 }
5356 break;
5357 }
5358 case DiskCache:
5359 {
5360 /*
5361 Write pixels to disk.
5362 */
5363 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5364 {
5365 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5366 cache_info->cache_filename);
5367 return(MagickFalse);
5368 }
5369 for (y=0; y < (long) rows; y++)
5370 {
5371 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5372 sizeof(*p),length,(const unsigned char *) p);
5373 if ((MagickSizeType) count < length)
5374 break;
5375 p+=nexus_info->region.width;
5376 offset+=cache_info->columns;
5377 }
5378 if (y < (long) rows)
5379 {
5380 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5381 cache_info->cache_filename);
5382 return(MagickFalse);
5383 }
5384 break;
5385 }
5386 default:
5387 break;
5388 }
5389 if ((cache_info->debug != MagickFalse) &&
5390 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5391 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5392 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5393 nexus_info->region.x,nexus_info->region.y);
5394 return(MagickTrue);
5395}