2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % AAA TTTTT TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
7 % A A T T R R I B B U U T E %
8 % AAAAA T T RRRR I BBBB U U T EEE %
9 % A A T T R R I B B U U T E %
10 % A A T T R R IIIII BBBB UUU T EEEEE %
13 % MagickCore Get / Set Image Attributes %
20 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/cache-view.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/colormap.h"
53 #include "MagickCore/colormap-private.h"
54 #include "MagickCore/colorspace.h"
55 #include "MagickCore/colorspace-private.h"
56 #include "MagickCore/composite.h"
57 #include "MagickCore/composite-private.h"
58 #include "MagickCore/constitute.h"
59 #include "MagickCore/draw.h"
60 #include "MagickCore/draw-private.h"
61 #include "MagickCore/effect.h"
62 #include "MagickCore/enhance.h"
63 #include "MagickCore/exception.h"
64 #include "MagickCore/exception-private.h"
65 #include "MagickCore/geometry.h"
66 #include "MagickCore/histogram.h"
67 #include "MagickCore/identify.h"
68 #include "MagickCore/image.h"
69 #include "MagickCore/image-private.h"
70 #include "MagickCore/list.h"
71 #include "MagickCore/log.h"
72 #include "MagickCore/memory_.h"
73 #include "MagickCore/magick.h"
74 #include "MagickCore/monitor.h"
75 #include "MagickCore/monitor-private.h"
76 #include "MagickCore/paint.h"
77 #include "MagickCore/pixel.h"
78 #include "MagickCore/pixel-accessor.h"
79 #include "MagickCore/property.h"
80 #include "MagickCore/quantize.h"
81 #include "MagickCore/quantum-private.h"
82 #include "MagickCore/random_.h"
83 #include "MagickCore/resource_.h"
84 #include "MagickCore/semaphore.h"
85 #include "MagickCore/segment.h"
86 #include "MagickCore/splay-tree.h"
87 #include "MagickCore/string_.h"
88 #include "MagickCore/thread-private.h"
89 #include "MagickCore/threshold.h"
90 #include "MagickCore/transform.h"
91 #include "MagickCore/utility.h"
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 + G e t I m a g e B o u n d i n g B o x %
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 % GetImageBoundingBox() returns the bounding box of an image canvas.
106 % The format of the GetImageBoundingBox method is:
108 % RectangleInfo GetImageBoundingBox(const Image *image,
109 % ExceptionInfo *exception)
111 % A description of each parameter follows:
113 % o bounds: Method GetImageBoundingBox returns the bounding box of an
116 % o image: the image.
118 % o exception: return any errors or warnings in this structure.
121 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
122 ExceptionInfo *exception)
137 register const Quantum
143 assert(image != (Image *) NULL);
144 assert(image->signature == MagickSignature);
145 if (image->debug != MagickFalse)
146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
149 bounds.x=(ssize_t) image->columns;
150 bounds.y=(ssize_t) image->rows;
151 GetPixelInfo(image,&target[0]);
152 image_view=AcquireCacheView(image);
153 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
154 if (p == (const Quantum *) NULL)
156 image_view=DestroyCacheView(image_view);
159 GetPixelInfoPixel(image,p,&target[0]);
160 GetPixelInfo(image,&target[1]);
161 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
163 GetPixelInfoPixel(image,p,&target[1]);
164 GetPixelInfo(image,&target[2]);
165 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
167 GetPixelInfoPixel(image,p,&target[2]);
169 GetPixelInfo(image,&zero);
170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
171 #pragma omp parallel for schedule(dynamic,4) shared(status)
173 for (y=0; y < (ssize_t) image->rows; y++)
181 register const Quantum
187 if (status == MagickFalse)
189 #if defined(MAGICKCORE_OPENMP_SUPPORT)
190 # pragma omp critical (MagickCore_GetImageBoundingBox)
193 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
194 if (p == (const Quantum *) NULL)
200 for (x=0; x < (ssize_t) image->columns; x++)
202 GetPixelInfoPixel(image,p,&pixel);
203 if ((x < bounding_box.x) &&
204 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
206 if ((x > (ssize_t) bounding_box.width) &&
207 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
208 bounding_box.width=(size_t) x;
209 if ((y < bounding_box.y) &&
210 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
212 if ((y > (ssize_t) bounding_box.height) &&
213 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
214 bounding_box.height=(size_t) y;
215 p+=GetPixelChannels(image);
217 #if defined(MAGICKCORE_OPENMP_SUPPORT)
218 # pragma omp critical (MagickCore_GetImageBoundingBox)
221 if (bounding_box.x < bounds.x)
222 bounds.x=bounding_box.x;
223 if (bounding_box.y < bounds.y)
224 bounds.y=bounding_box.y;
225 if (bounding_box.width > bounds.width)
226 bounds.width=bounding_box.width;
227 if (bounding_box.height > bounds.height)
228 bounds.height=bounding_box.height;
231 image_view=DestroyCacheView(image_view);
232 if ((bounds.width == 0) || (bounds.height == 0))
233 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
234 "GeometryDoesNotContainImage","`%s'",image->filename);
237 bounds.width-=(bounds.x-1);
238 bounds.height-=(bounds.y-1);
244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248 % G e t I m a g e D e p t h %
252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254 % GetImageDepth() returns the depth of a particular image channel.
256 % The format of the GetImageDepth method is:
258 % size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
260 % A description of each parameter follows:
262 % o image: the image.
264 % o exception: return any errors or warnings in this structure.
267 MagickExport size_t GetImageDepth(const Image *image,
268 ExceptionInfo *exception)
290 assert(image != (Image *) NULL);
291 assert(image->signature == MagickSignature);
292 if (image->debug != MagickFalse)
293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
294 number_threads=GetOpenMPMaximumThreads();
295 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
296 sizeof(*current_depth));
297 if (current_depth == (size_t *) NULL)
298 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
300 for (id=0; id < (ssize_t) number_threads; id++)
302 if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
304 register const PixelInfo
311 #if defined(MAGICKCORE_OPENMP_SUPPORT)
312 #pragma omp parallel for schedule(dynamic,4) shared(status)
314 for (i=0; i < (ssize_t) image->colors; i++)
317 id = GetOpenMPThreadId();
319 if (status == MagickFalse)
321 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
330 range=GetQuantumRange(current_depth[id]);
331 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
332 status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
334 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
335 status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
337 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
338 status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
346 depth=current_depth[0];
347 for (id=1; id < (ssize_t) number_threads; id++)
348 if (depth < current_depth[id])
349 depth=current_depth[id];
350 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
353 image_view=AcquireCacheView(image);
354 #if defined(MAGICKCORE_OPENMP_SUPPORT)
355 #pragma omp parallel for schedule(dynamic,4) shared(status)
357 for (y=0; y < (ssize_t) image->rows; y++)
360 id = GetOpenMPThreadId();
362 register const Quantum
368 if (status == MagickFalse)
370 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
371 if (p == (const Quantum *) NULL)
373 for (x=0; x < (ssize_t) image->columns; x++)
378 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
386 channel=GetPixelChannelMapChannel(image,i);
387 traits=GetPixelChannelMapTraits(image,channel);
388 if (traits == UndefinedPixelTrait)
390 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
399 range=GetQuantumRange(current_depth[id]);
400 status|=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
407 p+=GetPixelChannels(image);
409 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
412 image_view=DestroyCacheView(image_view);
413 depth=current_depth[0];
414 for (id=1; id < (ssize_t) number_threads; id++)
415 if (depth < current_depth[id])
416 depth=current_depth[id];
417 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426 % G e t I m a g e Q u a n t u m D e p t h %
430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432 % GetImageQuantumDepth() returns the depth of the image rounded to a legal
433 % quantum depth: 8, 16, or 32.
435 % The format of the GetImageQuantumDepth method is:
437 % size_t GetImageQuantumDepth(const Image *image,
438 % const MagickBooleanType constrain)
440 % A description of each parameter follows:
442 % o image: the image.
444 % o constrain: A value other than MagickFalse, constrains the depth to
445 % a maximum of MAGICKCORE_QUANTUM_DEPTH.
449 static inline double MagickMin(const double x,const double y)
456 MagickExport size_t GetImageQuantumDepth(const Image *image,
457 const MagickBooleanType constrain)
474 if (constrain != MagickFalse)
475 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % G e t I m a g e T y p e %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 % GetImageType() returns the potential type of image:
492 % Bilevel Grayscale GrayscaleMatte
493 % Palette PaletteMatte TrueColor
494 % TrueColorMatte ColorSeparation ColorSeparationMatte
496 % To ensure the image type matches its potential, use SetImageType():
498 % (void) SetImageType(image,GetImageType(image));
500 % The format of the GetImageType method is:
502 % ImageType GetImageType(const Image *image,ExceptionInfo *exception)
504 % A description of each parameter follows:
506 % o image: the image.
508 % o exception: return any errors or warnings in this structure.
511 MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
513 assert(image != (Image *) NULL);
514 assert(image->signature == MagickSignature);
515 if (image->debug != MagickFalse)
516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
517 if (image->colorspace == CMYKColorspace)
519 if (image->matte == MagickFalse)
520 return(ColorSeparationType);
521 return(ColorSeparationMatteType);
523 if (IsImageMonochrome(image,exception) != MagickFalse)
525 if (IsImageGray(image,exception) != MagickFalse)
527 if (image->matte != MagickFalse)
528 return(GrayscaleMatteType);
529 return(GrayscaleType);
531 if (IsPaletteImage(image,exception) != MagickFalse)
533 if (image->matte != MagickFalse)
534 return(PaletteMatteType);
537 if (image->matte != MagickFalse)
538 return(TrueColorMatteType);
539 return(TrueColorType);
543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547 % I s I m a g e G r a y %
551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
553 % IsImageGray() returns MagickTrue if all the pixels in the image have the
554 % same red, green, and blue intensities.
556 % The format of the IsImageGray method is:
558 % MagickBooleanType IsImageGray(const Image *image,
559 % ExceptionInfo *exception)
561 % A description of each parameter follows:
563 % o image: the image.
565 % o exception: return any errors or warnings in this structure.
568 MagickExport MagickBooleanType IsImageGray(const Image *image,
569 ExceptionInfo *exception)
577 register const Quantum
586 assert(image != (Image *) NULL);
587 assert(image->signature == MagickSignature);
588 if (image->debug != MagickFalse)
589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
590 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
591 (image->type == GrayscaleMatteType))
593 if (IsRGBColorspace(image->colorspace) == MagickFalse)
596 image_view=AcquireCacheView(image);
597 for (y=0; y < (ssize_t) image->rows; y++)
599 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
600 if (p == (const Quantum *) NULL)
602 for (x=0; x < (ssize_t) image->columns; x++)
604 if (IsPixelGray(image,p) == MagickFalse)
609 if ((type == BilevelType) &&
610 (IsPixelMonochrome(image,p) == MagickFalse))
612 p+=GetPixelChannels(image);
614 if (type == UndefinedType)
617 image_view=DestroyCacheView(image_view);
618 if (type == UndefinedType)
620 ((Image *) image)->type=type;
621 if ((type == GrayscaleType) && (image->matte != MagickFalse))
622 ((Image *) image)->type=GrayscaleMatteType;
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631 % I s I m a g e M o n o c h r o m e %
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637 % IsImageMonochrome() returns MagickTrue if all the pixels in the image have
638 % the same red, green, and blue intensities and the intensity is either
641 % The format of the IsImageMonochrome method is:
643 % MagickBooleanType IsImageMonochrome(const Image *image,
644 % ExceptionInfo *exception)
646 % A description of each parameter follows:
648 % o image: the image.
650 % o exception: return any errors or warnings in this structure.
653 MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
654 ExceptionInfo *exception)
665 register const Quantum
671 assert(image != (Image *) NULL);
672 assert(image->signature == MagickSignature);
673 if (image->debug != MagickFalse)
674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
675 if (image->type == BilevelType)
677 if (IsRGBColorspace(image->colorspace) == MagickFalse)
680 image_view=AcquireCacheView(image);
681 for (y=0; y < (ssize_t) image->rows; y++)
683 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
684 if (p == (const Quantum *) NULL)
686 for (x=0; x < (ssize_t) image->columns; x++)
688 if (IsPixelMonochrome(image,p) == MagickFalse)
693 p+=GetPixelChannels(image);
695 if (type == UndefinedType)
698 image_view=DestroyCacheView(image_view);
699 if (type == UndefinedType)
701 ((Image *) image)->type=type;
706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 % I s I m a g e O p a q u e %
714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 % IsImageOpaque() returns MagickTrue if none of the pixels in the image have
717 % an opacity value other than opaque (0).
719 % The format of the IsImageOpaque method is:
721 % MagickBooleanType IsImageOpaque(const Image *image,
722 % ExceptionInfo *exception)
724 % A description of each parameter follows:
726 % o image: the image.
728 % o exception: return any errors or warnings in this structure.
731 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
732 ExceptionInfo *exception)
737 register const Quantum
747 Determine if image is opaque.
749 assert(image != (Image *) NULL);
750 assert(image->signature == MagickSignature);
751 if (image->debug != MagickFalse)
752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
753 if (image->matte == MagickFalse)
755 image_view=AcquireCacheView(image);
756 for (y=0; y < (ssize_t) image->rows; y++)
758 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
759 if (p == (const Quantum *) NULL)
761 for (x=0; x < (ssize_t) image->columns; x++)
763 if (GetPixelAlpha(image,p) != OpaqueAlpha)
765 p+=GetPixelChannels(image);
767 if (x < (ssize_t) image->columns)
770 image_view=DestroyCacheView(image_view);
771 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779 % S e t I m a g e D e p t h %
783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785 % SetImageDepth() sets the depth of the image.
787 % The format of the SetImageDepth method is:
789 % MagickBooleanType SetImageDepth(Image *image,const size_t depth,
790 % ExceptionInfo *exception)
792 % A description of each parameter follows:
794 % o image: the image.
796 % o channel: the channel.
798 % o depth: the image depth.
800 % o exception: return any errors or warnings in this structure.
803 MagickExport MagickBooleanType SetImageDepth(Image *image,
804 const size_t depth,ExceptionInfo *exception)
818 assert(image != (Image *) NULL);
819 if (image->debug != MagickFalse)
820 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
821 assert(image->signature == MagickSignature);
822 if (GetImageDepth(image,exception) <= (size_t)
823 MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
829 Scale pixels to desired depth.
832 range=GetQuantumRange(depth);
833 image_view=AcquireCacheView(image);
834 #if defined(MAGICKCORE_OPENMP_SUPPORT)
835 #pragma omp parallel for schedule(dynamic,4) shared(status)
837 for (y=0; y < (ssize_t) image->rows; y++)
845 if (status == MagickFalse)
847 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
848 if (q == (Quantum *) NULL)
853 for (x=0; x < (ssize_t) image->columns; x++)
858 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
866 channel=GetPixelChannelMapChannel(image,i);
867 traits=GetPixelChannelMapTraits(image,channel);
868 if (traits == UndefinedPixelTrait)
870 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
872 q+=GetPixelChannels(image);
874 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
880 image_view=DestroyCacheView(image_view);
881 if (image->storage_class == PseudoClass)
890 #if defined(MAGICKCORE_OPENMP_SUPPORT)
891 #pragma omp parallel for schedule(dynamic,4) shared(status)
893 for (i=0; i < (ssize_t) image->colors; i++)
895 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
896 p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
897 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
898 p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
899 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
900 p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
901 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
902 p->alpha=ScaleAnyToQuantum(ScaleQuantumToAny(p->alpha,range),range);