-
-static inline MagickRealType Atop(const MagickRealType p,
- const MagickRealType Sa,const MagickRealType q,
- const MagickRealType magick_unused(Da))
-{
- return(p*Sa+q*(1.0-Sa)); /* Da optimized out, Da/gamma => 1.0 */
-}
-
-static inline void CompositeAtop(const PixelInfo *p,const PixelInfo *q,
- PixelInfo *composite)
-{
- MagickRealType
- Sa;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- composite->alpha=q->alpha; /* optimized Da = 1.0-Gamma */
- composite->red=Atop(p->red,Sa,q->red,1.0);
- composite->green=Atop(p->green,Sa,q->green,1.0);
- composite->blue=Atop(p->blue,Sa,q->blue,1.0);
- if (q->colorspace == CMYKColorspace)
- composite->black=Atop(p->black,Sa,q->black,1.0);
-}
-
-/*
- Bumpmap: Multiply by overlay intensity
- What is this Composition actually method for? Can't find any specification!
-
- I think this was meant to be a 'HardLight effect' using a Shaded Image!
- That is a Embossing, using a height map! Better to do it piecemeal.
-*/
-static inline void CompositeBumpmap(const PixelInfo *p,const PixelInfo *q,
- PixelInfo *composite)
-{
- MagickRealType
- intensity;
-
- intensity=(MagickRealType) GetPixelInfoIntensity(p);
- composite->red=QuantumScale*intensity*q->red;
- composite->green=QuantumScale*intensity*q->green;
- composite->blue=QuantumScale*intensity*q->blue;
- composite->alpha=(MagickRealType) QuantumScale*intensity*p->alpha;
- if (q->colorspace == CMYKColorspace)
- composite->black=QuantumScale*intensity*q->black;
-}
-
-static inline void CompositeClear(const PixelInfo *q,PixelInfo *composite)
-{
- composite->alpha=(MagickRealType) TransparentAlpha;
- composite->red=0.0;
- composite->green=0.0;
- composite->blue=0.0;
- composite->black=1.0;
-}
-
-static MagickRealType ColorBurn(const MagickRealType Sca,
- const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
-{
- if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
- return(Sa*Da+Dca*(1.0-Sa));
- if (Sca < MagickEpsilon)
- return(Dca*(1.0-Sa));
- return(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeColorBurn(const PixelInfo *p,const PixelInfo *q,
- PixelInfo *composite)
-{
- MagickRealType
- Da,
- gamma,
- Sa;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- Da=QuantumScale*q->alpha;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->alpha=(MagickRealType) QuantumRange*gamma;
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*ColorBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da);
- composite->green=gamma*ColorBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da);
- composite->blue=gamma*ColorBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*ColorBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
- q->black*Da,Da);
-}
-
-
-static MagickRealType ColorDodge(const MagickRealType Sca,
- const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
- /*
- Working from first principles using the original formula:
-
- f(Sc,Dc) = Dc/(1-Sc)
-
- This works correctly! Looks like the 2004 SVG model was right but just
- required a extra condition for correct handling.
- */
- if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
- return(Sca*(1.0-Da)+Dca*(1.0-Sa));
- if (fabs(Sca-Sa) < MagickEpsilon)
- return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
- return(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeColorDodge(const PixelInfo *p,const PixelInfo *q,
- PixelInfo *composite)
-{
- MagickRealType
- Da,
- gamma,
- Sa;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- Da=QuantumScale*q->alpha;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->alpha=(MagickRealType) QuantumRange*gamma;
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*ColorDodge(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da);
- composite->green=gamma*ColorDodge(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da);
- composite->blue=gamma*ColorDodge(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*ColorDodge(QuantumScale*p->black*Sa,Sa,QuantumScale*
- q->black*Da,Da);
-}
-
-static inline MagickRealType Darken(const MagickRealType p,
- const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
-{
- if (p < q)
- return(MagickOver_(p,alpha,q,beta)); /* src-over */
- return(MagickOver_(q,beta,p,alpha)); /* dst-over */
-}
-
-static inline void CompositeDarken(const Image *image,const PixelInfo *p,
- const PixelInfo *q,PixelInfo *composite)
-{
- MagickRealType
- gamma;
-
- /*
- Darken is equivalent to a 'Minimum' method OR a greyscale version of a
- binary 'Or' OR the 'Intersection' of pixel sets.
- */
- if (image->channel_mask != DefaultChannels)
- {
- /*
- Handle channels as separate grayscale channels.
- */
- if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
- composite->red=MagickMin(p->red,q->red);
- if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
- composite->green=MagickMin(p->green,q->green);
- if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
- composite->blue=MagickMin(p->blue,q->blue);
- if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0 &&
- (q->colorspace == CMYKColorspace))
- composite->black=MagickMin(p->black,q->black);
- if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
- composite->alpha=MagickMax(p->alpha,q->alpha);
- return;
- }
- composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
- gamma=1.0-QuantumScale*composite->alpha;
- gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Darken(p->red,p->alpha,q->red,q->alpha);
- composite->green=gamma*Darken(p->green,p->alpha,q->green,q->alpha);
- composite->blue=gamma*Darken(p->blue,p->alpha,q->blue,q->alpha);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*Darken(p->black,p->alpha,q->black,q->alpha);
-}
-
-static inline void CompositeDarkenIntensity(const Image *image,
- const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
- MagickRealType
- Da,
- Sa;
-
- /*
- Select the pixel based on the intensity level.
- If 'Sync' flag select whole pixel based on alpha weighted intensity.
- Otherwise use intensity only, but restrict copy according to channel.
- */
- if (image->channel_mask != DefaultChannels)
- {
- MagickBooleanType
- from_p;
-
- from_p=GetPixelInfoIntensity(p) < GetPixelInfoIntensity(q) ? MagickTrue :
- MagickFalse;
- if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
- composite->red=from_p != MagickFalse ? p->red : q->red;
- if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
- composite->green=from_p != MagickFalse ? p->green : q->green;
- if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
- composite->blue=from_p != MagickFalse ? p->blue : q->blue;
- if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
- (q->colorspace == CMYKColorspace))
- composite->black=from_p != MagickFalse ? p->black : q->black;
- if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
- composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
- return;
- }
- Sa=QuantumScale*p->alpha;
- Da=QuantumScale*q->alpha;
- *composite=(Sa*GetPixelInfoIntensity(p) < Da*GetPixelInfoIntensity(q)) ?
- *p : *q;
-}
-
-static inline MagickRealType Difference(const MagickRealType p,
- const MagickRealType Sa,const MagickRealType q,const MagickRealType Da)
-{
- /*
- Optimized by Multipling by QuantumRange (taken from gamma).
- */
- return(Sa*p+Da*q-Sa*Da*2.0*MagickMin(p,q));
-}
-
-static inline void CompositeDifference(const Image *image,const PixelInfo *p,
- const PixelInfo *q,PixelInfo *composite)
-{
- MagickRealType
- Da,
- gamma,
- Sa;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- Da=QuantumScale*q->alpha;
- if (image->channel_mask != DefaultChannels)
- {
- /*
- Handle channels as separate grayscale channels.
- */
- if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
- composite->red=fabs((double) (p->red-q->red));
- if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
- composite->green=fabs((double) (p->green-q->green));
- if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
- composite->blue=fabs((double) (p->blue-q->blue));
- if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
- (q->colorspace == CMYKColorspace))
- composite->black=fabs((double) (p->black-q->black));
- if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
- composite->alpha=fabs((double) (p->alpha-q->alpha));
- return;
- }
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->alpha=(MagickRealType) QuantumRange*gamma;
- gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Difference(p->red,Sa,q->red,Da);
- composite->green=gamma*Difference(p->green,Sa,q->green,Da);
- composite->blue=gamma*Difference(p->blue,Sa,q->blue,Da);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*Difference(p->black,Sa,q->black,Da);
-}
-
-static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
- const MagickRealType Dca,const MagickRealType Da)
-{
- /*
- Divide Source by Destination
-
- f(Sc,Dc) = Sc / Dc
-
- But with appropriate handling for special case of Dc == 0 specifically
- so that f(Black,Black)=Black and f(non-Black,Black)=White.
- It is however also important to correctly do 'over' alpha blending which
- is why the formula becomes so complex.
- */
- if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
- return(Sca*(1.0-Da)+Dca*(1.0-Sa));
- if (fabs(Dca) < MagickEpsilon)
- return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
- return(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeDivide(const Image *image,const PixelInfo *p,
- const PixelInfo *q,PixelInfo *composite)
-{
- MagickRealType
- Da,
- gamma,
- Sa;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- Da=QuantumScale*q->alpha;
- if (image->channel_mask != DefaultChannels)
- {
- /*
- Handle channels as separate grayscale channels.
- */
- if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
- composite->red=QuantumRange*Divide(QuantumScale*p->red,1.0,
- QuantumScale*q->red,1.0);
- if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
- composite->green=QuantumRange*Divide(QuantumScale*p->green,1.0,
- QuantumScale*q->green,1.0);
- if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
- composite->blue=QuantumRange*Divide(QuantumScale*p->blue,1.0,
- QuantumScale*q->blue,1.0);
- if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
- (q->colorspace == CMYKColorspace))
- composite->black=QuantumRange*Divide(QuantumScale*p->black,1.0,
- QuantumScale*q->black,1.0);
- if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
- composite->alpha=QuantumRange*(1.0-Divide(Sa,1.0,Da,1.0));
- return;
- }
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->alpha=(MagickRealType) QuantumRange*gamma;
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Divide(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da);
- composite->green=gamma*Divide(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da);
- composite->blue=gamma*Divide(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*Divide(QuantumScale*p->black*Sa,Sa,QuantumScale*
- q->black*Da,Da);
-}
-
-static MagickRealType Exclusion(const MagickRealType Sca,
- const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
- return(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeExclusion(const Image *image,const PixelInfo *p,
- const PixelInfo *q,PixelInfo *composite)
-{
- MagickRealType
- gamma,
- Sa,
- Da;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- Da=QuantumScale*q->alpha;
- if (image->channel_mask != DefaultChannels)
- {
- /*
- Handle channels as separate grayscale channels.
- */
- if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
- composite->red=QuantumRange*Exclusion(QuantumScale*p->red,1.0,
- QuantumScale*q->red,1.0);
- if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
- composite->green=QuantumRange*Exclusion(QuantumScale*p->green,1.0,
- QuantumScale*q->green,1.0);
- if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
- composite->blue=QuantumRange*Exclusion(QuantumScale*p->blue,1.0,
- QuantumScale*q->blue,1.0);
- if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
- (q->colorspace == CMYKColorspace))
- composite->black=QuantumRange*Exclusion(QuantumScale*p->black,1.0,
- QuantumScale*q->black,1.0);
- if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
- composite->alpha=QuantumRange*(1.0-Exclusion(Sa,1.0,Da,1.0));
- return;
- }
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->alpha=(MagickRealType) QuantumRange*gamma;
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da);
- composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da);
- composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*Exclusion(QuantumScale*p->black*Sa,Sa,
- QuantumScale*q->black*Da,Da);
-}
-
-static MagickRealType HardLight(const MagickRealType Sca,
- const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
- if ((2.0*Sca) < Sa)
- return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
- return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeHardLight(const PixelInfo *p,const PixelInfo *q,
- PixelInfo *composite)
-{
- MagickRealType
- Da,
- gamma,
- Sa;
-
- Sa=QuantumScale*p->alpha; /* simplify and speed up equations */
- Da=QuantumScale*q->alpha;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->alpha=(MagickRealType) QuantumRange*gamma;
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da);
- composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da);
- composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da);
- if (q->colorspace == CMYKColorspace)
- composite->black=gamma*HardLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
- q->black*Da,Da);
-}
-
-static void CompositeHSB(const MagickRealType red,const MagickRealType green,
- const MagickRealType blue,double *hue,double *saturation,double *brightness)