% July 1992 %
% %
% %
-% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
#include "magick/resample.h"
#include "magick/resource_.h"
#include "magick/string_.h"
+#include "magick/thread-private.h"
#include "magick/utility.h"
#include "magick/version.h"
\f
%
% MagickBooleanType CompositeImage(Image *image,
% const CompositeOperator compose,Image *composite_image,
-% const long x_offset,const long y_offset)
+% const ssize_t x_offset,const ssize_t y_offset)
% MagickBooleanType CompositeImageChannel(Image *image,
% const ChannelType channel,const CompositeOperator compose,
-% Image *composite_image,const long x_offset,const long y_offset)
+% Image *composite_image,const ssize_t x_offset,const ssize_t y_offset)
%
% A description of each parameter follows:
%
** gamma = Sa+Da-Sa*Da;
** gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
** opacity = QuantiumScale*alpha*beta; // over blend, optimized 1-Gamma
+**
+** The above SVG definitions also definate that Mathematical Composition
+** methods should use a 'Over' blending mode for Alpha Channel.
+** It however was not applied for composition modes of 'Plus', 'Minus',
+** the modulus versions of 'Add' and 'Subtract'.
+**
+**
+** Mathematical operator changes to be applied from IM v6.7...
+**
+** 1/ Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
+** 'ModulusAdd' and 'ModulusSubtract' for clarity.
+**
+** 2/ All mathematical compositions work as per the SVG specification
+** with regard to blending. This now includes 'ModulusAdd' and
+** 'ModulusSubtract'.
+**
+** 3/ When the special channel flag 'sync' (syncronize channel updates)
+** is turned off (enabled by default) then mathematical compositions are
+** only performed on the channels specified, and are applied
+** independantally of each other. In other words the mathematics is
+** performed as 'pure' mathematical operations, rather than as image
+** operations.
*/
-static inline MagickRealType Add(const MagickRealType p,const MagickRealType q)
-{
- MagickRealType
- pixel;
-
- pixel=p+q;
- if (pixel > QuantumRange)
- pixel-=(QuantumRange+1.0);
- return(pixel);
-}
-
-static inline void CompositeAdd(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
-{
- composite->red=Add(p->red,q->red);
- composite->green=Add(p->green,q->green);
- composite->blue=Add(p->blue,q->blue);
- composite->opacity=Add(alpha,beta);
- if (q->colorspace == CMYKColorspace)
- composite->index=Add(p->index,q->index);
-}
-
static inline MagickRealType Atop(const MagickRealType p,
const MagickRealType Sa,const MagickRealType q,
const MagickRealType magick_unused(Da))
}
static inline void CompositeAtop(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- composite->opacity=beta; /* optimized 1.0-Gamma */
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ composite->opacity=q->opacity; /* 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);
}
/*
- What is this Composition method for, can't find any specification!
+ What is this Composition method for? Can't find any specification!
WARNING this is not doing correct 'over' blend handling (Anthony Thyssen).
*/
static inline void CompositeBumpmap(const MagickPixelPacket *p,
- const MagickRealType magick_unused(alpha),const MagickPixelPacket *q,
- const MagickRealType magick_unused(beta),MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
intensity;
composite->red=QuantumScale*intensity*q->red;
composite->green=QuantumScale*intensity*q->green;
composite->blue=QuantumScale*intensity*q->blue;
- composite->opacity=(MagickRealType) QuantumScale*intensity*p->opacity;
+ composite->opacity=(MagickRealType) QuantumScale*intensity*
+ GetOpacityPixelComponent(p);
if (q->colorspace == CMYKColorspace)
composite->index=QuantumScale*intensity*q->index;
}
}
static inline void CompositeColorBurn(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
}
static inline void CompositeColorDodge(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
}
static inline void CompositeDarken(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
+ /*
+ Darken is equivelent to a 'Minimum' method
+ OR a greyscale version of a binary 'Or'
+ OR the 'Intersection' of pixel sets.
+ */
MagickRealType
gamma;
- gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
- composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Darken(p->red,alpha,q->red,beta);
- composite->green=gamma*Darken(p->green,alpha,q->green,beta);
- composite->blue=gamma*Darken(p->blue,alpha,q->blue,beta);
- if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Darken(p->index,alpha,q->index,beta);
+ if ( (channel & SyncChannels) != 0 ) {
+ composite->opacity=QuantumScale*p->opacity*q->opacity; /* Over Blend */
+ gamma=1.0-QuantumScale*composite->opacity;
+ gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=gamma*Darken(p->red,p->opacity,q->red,q->opacity);
+ composite->green=gamma*Darken(p->green,p->opacity,q->green,q->opacity);
+ composite->blue=gamma*Darken(p->blue,p->opacity,q->blue,q->opacity);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=gamma*Darken(p->index,p->opacity,q->index,q->opacity);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=MagickMax(p->opacity,q->opacity);
+ if ( (channel & RedChannel) != 0 )
+ composite->red=MagickMin(p->red,q->red);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=MagickMin(p->green,q->green);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=MagickMin(p->blue,q->blue);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=MagickMin(p->index,q->index);
+ }
}
static inline MagickRealType Difference(const MagickRealType p,
const MagickRealType Sa,const MagickRealType q,const MagickRealType Da)
{
- /*
- Optimized by Multipling by QuantumRange (taken from gamma).
- */
+ /* 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 MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- /*
- Values not normalized as an optimization.
- */
- 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->index=gamma*Difference(p->index,Sa,q->index,Da);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ /* Values are not normalized as an optimization. */
+ 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->index=gamma*Difference(p->index,Sa,q->index,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange-fabs(p->opacity - q->opacity);
+ if ( (channel & RedChannel) != 0 )
+ composite->red=fabs(p->red - q->red);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=fabs(p->green - q->green);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=fabs(p->blue - q->blue);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=fabs(p->index - q->index);
+ }
}
static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
f(Sc,Dc) = Sc/Dc
But with appropriate handling for special case of Dc == 0 specifically
- f(Black,Black) = Black and f(non-Black,Black) = White. It is however
- also important to correctly do 'over' alpha blending which is why it
- becomes so complex looking.
+ 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 looking.
*/
if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
return(Sca*(1.0-Da)+Dca*(1.0-Sa));
}
static inline void CompositeDivide(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Divide(QuantumScale*p->index*Sa,Sa,QuantumScale*
- q->index*Da,Da);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Divide(QuantumScale*p->index*Sa,Sa,QuantumScale*
+ q->index*Da,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange*(1.0-Divide(Sa,1.0,Da,1.0));
+ if ( (channel & RedChannel) != 0 )
+ composite->red=QuantumRange*
+ Divide(QuantumScale*p->red,1.0,QuantumScale*q->red,1.0);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=QuantumRange*
+ Divide(QuantumScale*p->green,1.0,QuantumScale*q->green,1.0);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=QuantumRange*
+ Divide(QuantumScale*p->blue,1.0,QuantumScale*q->blue,1.0);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=QuantumRange*
+ Divide(QuantumScale*p->index,1.0,QuantumScale*q->index,1.0);
+ }
}
static MagickRealType Exclusion(const MagickRealType Sca,
}
static inline void CompositeExclusion(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
MagickRealType
gamma,
Sa,
Da;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Exclusion(QuantumScale*p->index*Sa,Sa,QuantumScale*
- q->index*Da,Da);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-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->index=gamma*Exclusion(QuantumScale*p->index*Sa,Sa,QuantumScale*
+ q->index*Da,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange*(1.0-Exclusion(Sa,1.0,Da,1.0));
+ if ( (channel & RedChannel) != 0 )
+ composite->red=QuantumRange*
+ Exclusion(QuantumScale*p->red,1.0,QuantumScale*q->red,1.0);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=QuantumRange*
+ Exclusion(QuantumScale*p->green,1.0,QuantumScale*q->green,1.0);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=QuantumRange*
+ Exclusion(QuantumScale*p->blue,1.0,QuantumScale*q->blue,1.0);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=QuantumRange*
+ Exclusion(QuantumScale*p->index,1.0,QuantumScale*q->index,1.0);
+ }
}
static MagickRealType HardLight(const MagickRealType Sca,
}
static inline void CompositeHardLight(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
q->index*Da,Da);
}
-
static void CompositeHSB(const MagickRealType red,const MagickRealType green,
const MagickRealType blue,double *hue,double *saturation,double *brightness)
{
}
static inline MagickRealType In(const MagickRealType p,
- const MagickRealType alpha,const MagickRealType magick_unused(q),
- const MagickRealType beta)
+ const MagickRealType Sa,const MagickRealType magick_unused(q),
+ const MagickRealType Da)
{
- return((1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta));
+ return(Sa*p*Da);
}
static inline void CompositeIn(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
- gamma;
+ gamma,
+ Sa,
+ Da;
- gamma=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ gamma=Sa*Da;
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*In(p->red,alpha,q->red,beta);
- composite->green=gamma*In(p->green,alpha,q->green,beta);
- composite->blue=gamma*In(p->blue,alpha,q->blue,beta);
+ composite->red=gamma*In(p->red,Sa,q->red,Da);
+ composite->green=gamma*In(p->green,Sa,q->green,Da);
+ composite->blue=gamma*In(p->blue,Sa,q->blue,Da);
if (q->colorspace == CMYKColorspace)
- composite->index=gamma*In(p->index,alpha,q->index,beta);
+ composite->index=gamma*In(p->index,Sa,q->index,Da);
}
static inline MagickRealType Lighten(const MagickRealType p,
}
static inline void CompositeLighten(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
+ /*
+ Lighten is also equivelevt to a 'Maximum' method
+ OR a greyscale version of a binary 'And'
+ OR the 'Union' of pixel sets.
+ */
MagickRealType
gamma;
- composite->opacity=QuantumScale*alpha*beta; /* optimized 1-gamma */
- gamma=1.0-QuantumScale*composite->opacity;
- gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Lighten(p->red,alpha,q->red,beta);
- composite->green=gamma*Lighten(p->green,alpha,q->green,beta);
- composite->blue=gamma*Lighten(p->blue,alpha,q->blue,beta);
- if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Lighten(p->index,alpha,q->index,beta);
+ if ( (channel & SyncChannels) != 0 ) {
+ composite->opacity=QuantumScale*p->opacity*q->opacity; /* Over Blend */
+ gamma=1.0-QuantumScale*composite->opacity;
+ gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=gamma*Lighten(p->red,p->opacity,q->red,q->opacity);
+ composite->green=gamma*Lighten(p->green,p->opacity,q->green,q->opacity);
+ composite->blue=gamma*Lighten(p->blue,p->opacity,q->blue,q->opacity);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=gamma*Lighten(p->index,p->opacity,q->index,q->opacity);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=MagickMin(p->opacity,q->opacity);
+ if ( (channel & RedChannel) != 0 )
+ composite->red=MagickMax(p->red,q->red);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=MagickMax(p->green,q->green);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=MagickMax(p->blue,q->blue);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=MagickMax(p->index,q->index);
+ }
}
+#if 0
+static inline MagickRealType LinearDodge(const MagickRealType Sca,
+ const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+{
+ /*
+ LinearDodge: simplifies to a trivial formula
+ f(Sc,Dc) = Sc + Dc
+ Dca' = Sca + Dca
+ */
+ return(Sca+Dca);
+}
+#endif
+
static inline void CompositeLinearDodge(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- /*
- Operation performed directly - not need for sub-routine.
- */
gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
composite->red=gamma*(p->red*Sa+q->red*Da);
composite->green=gamma*(p->green*Sa+q->green*Da);
const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
{
/*
- LinearLight: as defined by Abode Photoshop, according to
+ LinearBurn: as defined by Abode Photoshop, according to
http://www.simplefilter.de/en/basics/mixmods.html is:
- f(Sc,Dc) = Dc + Sc - 1
+ f(Sc,Dc) = Sc + Dc - 1
*/
return(Sca+Dca-Sa*Da);
}
static inline void CompositeLinearBurn(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
q->index*Da,Da);
}
-
static inline MagickRealType LinearLight(const MagickRealType Sca,
const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
{
#if 0
/*
- Previous formula, only valid for fully-opaque images.
+ Previous formula, was only valid for fully-opaque images.
*/
return(Dca+2*Sca-1.0);
#else
}
static inline void CompositeLinearLight(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
}
static inline void CompositeMathematics(const MagickPixelPacket *p,
- const MagickPixelPacket *q,const GeometryInfo *args,
- MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel, const GeometryInfo
+ *args, MagickPixelPacket *composite)
{
MagickRealType
+ Sa,
Da,
- gamma,
- Sa;
+ gamma;
- Sa=1.0-QuantumScale*p->opacity;
+ Sa=1.0-QuantumScale*GetOpacityPixelComponent(p); /* ??? - AT */
Da=1.0-QuantumScale*q->opacity;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Mathematics(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da,args);
- composite->green=gamma*Mathematics(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da,args);
- composite->blue=gamma*Mathematics(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da,args);
- if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Mathematics(QuantumScale*p->index*Sa,Sa,QuantumScale*
- q->index*Da,Da,args);
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=gamma*Mathematics(QuantumScale*p->red*Sa,Sa,QuantumScale*
+ q->red*Da,Da,args);
+ composite->green=gamma*Mathematics(QuantumScale*p->green*Sa,Sa,QuantumScale*
+ q->green*Da,Da,args);
+ composite->blue=gamma*Mathematics(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+ q->blue*Da,Da,args);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=gamma*Mathematics(QuantumScale*p->index*Sa,Sa,QuantumScale*
+ q->index*Da,Da,args);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange*(1.0-Mathematics(Sa,1.0,Da,1.0,args));
+ if ( (channel & RedChannel) != 0 )
+ composite->red=QuantumRange*
+ Mathematics(QuantumScale*p->red,1.0,QuantumScale*q->red,1.0,args);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=QuantumRange*
+ Mathematics(QuantumScale*p->green,1.0,QuantumScale*q->green,1.0,args);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=QuantumRange*
+ Mathematics(QuantumScale*p->blue,1.0,QuantumScale*q->blue,1.0,args);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=QuantumRange*
+ Mathematics(QuantumScale*p->index,1.0,QuantumScale*q->index,1.0,args);
+ }
+
+}
+
+static inline void CompositePlus(const MagickPixelPacket *p,
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
+{
+ if ( (channel & SyncChannels) != 0 ) {
+ /*
+ NOTE: "Plus" does not use 'over' alpha-blending but uses a
+ special 'plus' form of alph-blending. It is the ONLY mathematical
+ operator to do this. this is what makes it different to the
+ otherwise equivelent "LinearDodge" composition method.
+
+ Note however that color channels are still effected by the alpha channel
+ as a result of the blending, making it just as useless for independant
+ channel maths, just like all other mathematical composition methods.
+
+ As such the removal of the 'sync' flag, is still a usful convention.
+
+ The MagickPixelCompositePlus() function is defined in
+ "composite-private.h" so it can also be used for Image Blending.
+ */
+ MagickPixelCompositePlus(p,p->opacity,q,q->opacity,composite);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=p->opacity+q->opacity-QuantumRange;
+ if ( (channel & RedChannel) != 0 )
+ composite->red=p->red+q->red;
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=p->green+q->green;
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=p->blue+q->blue;
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=p->index+q->index;
+ }
}
static inline MagickRealType Minus(const MagickRealType Sca,
- const MagickRealType Dca)
+ const MagickRealType Sa,const MagickRealType Dca,
+ const MagickRealType magick_unused(Da))
{
- return(Sca-Dca);
+ return(Sca + Dca - 2*Dca*Sa);
}
static inline void CompositeMinus(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
MagickRealType
+ Sa,
Da,
- gamma,
- Sa;
+ gamma;
- Sa=1.0-QuantumScale*alpha;
- Da=1.0-QuantumScale*beta;
- gamma=RoundToUnity(Sa-Da); /* is this correct? - I do not think so! */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Minus(p->red*Sa,q->red*Da);
- composite->green=gamma*Minus(p->green*Sa,q->green*Da);
- composite->blue=gamma*Minus(p->blue*Sa,q->blue*Da);
- if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Minus(p->index*Sa,q->index*Da);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=gamma*Minus(p->red*Sa,Sa,q->red*Da,Da);
+ composite->green=gamma*Minus(p->green*Sa,Sa,q->green*Da,Da);
+ composite->blue=gamma*Minus(p->blue*Sa,Sa,q->blue*Da,Da);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=gamma*Minus(p->index*Sa,Sa,q->index*Da,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange*(1.0-(Sa-Da));
+ if ( (channel & RedChannel) != 0 )
+ composite->red=p->red-q->red;
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=p->green-q->green;
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=p->blue-q->blue;
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=p->index-q->index;
+ }
+}
+
+static inline MagickRealType ModulusAdd(const MagickRealType p,
+ const MagickRealType Sa, const MagickRealType q, const MagickRealType Da)
+{
+ MagickRealType
+ pixel;
+
+ pixel=p+q;
+ if (pixel > QuantumRange)
+ pixel-=(QuantumRange+1.0);
+ return(pixel*Sa*Da + p*Sa*(1-Da) + q*Da*(1-Sa));
+}
+
+static inline void CompositeModulusAdd(const MagickPixelPacket *p,
+ const MagickPixelPacket *q, const ChannelType channel,
+ MagickPixelPacket *composite)
+{
+ if ( (channel & SyncChannels) != 0 ) {
+ MagickRealType
+ Sa,
+ Da,
+ gamma;
+
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=ModulusAdd(p->red,Sa,q->red,Da);
+ composite->green=ModulusAdd(p->green,Sa,q->green,Da);
+ composite->blue=ModulusAdd(p->blue,Sa,q->blue,Da);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=ModulusAdd(p->index,Sa,q->index,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange-ModulusAdd(QuantumRange-p->opacity,
+ 1.0,QuantumRange-q->opacity,1.0);
+ if ( (channel & RedChannel) != 0 )
+ composite->red=ModulusAdd(p->red,1.0,q->red,1.0);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=ModulusAdd(p->green,1.0,q->green,1.0);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=ModulusAdd(p->blue,1.0,q->blue,1.0);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=ModulusAdd(p->index,1.0,q->index,1.0);
+ }
+}
+
+static inline MagickRealType ModulusSubtract(const MagickRealType p,
+ const MagickRealType Sa, const MagickRealType q, const MagickRealType Da)
+{
+ MagickRealType
+ pixel;
+
+ pixel=p-q;
+ if (pixel < 0.0)
+ pixel+=(QuantumRange+1.0);
+ return(pixel*Sa*Da + p*Sa*(1-Da) + q*Da*(1-Sa));
+}
+
+static inline void CompositeModulusSubtract(const MagickPixelPacket *p,
+ const MagickPixelPacket *q, const ChannelType channel,
+ MagickPixelPacket *composite)
+{
+ if ( (channel & SyncChannels) != 0 ) {
+ MagickRealType
+ Sa,
+ Da,
+ gamma;
+
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ gamma = RoundToUnity(Sa+Da-Sa*Da);
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=ModulusSubtract(p->red,Sa,q->red,Da);
+ composite->green=ModulusSubtract(p->green,Sa,q->green,Da);
+ composite->blue=ModulusSubtract(p->blue,Sa,q->blue,Da);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=ModulusSubtract(p->index,Sa,q->index,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange-ModulusSubtract(QuantumRange-p->opacity,
+ 1.0,QuantumRange-q->opacity,1.0);
+ if ( (channel & RedChannel) != 0 )
+ composite->red=ModulusSubtract(p->red,1.0,q->red,1.0);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=ModulusSubtract(p->green,1.0,q->green,1.0);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=ModulusSubtract(p->blue,1.0,q->blue,1.0);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=ModulusSubtract(p->index,1.0,q->index,1.0);
+ }
}
static inline MagickRealType Multiply(const MagickRealType Sca,
}
static inline void CompositeMultiply(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha;
- Da=1.0-QuantumScale*beta;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
- q->red*Da,Da);
- composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
- q->green*Da,Da);
- composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
- q->blue*Da,Da);
- if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Multiply(QuantumScale*p->index*Sa,Sa,QuantumScale*
- q->index*Da,Da);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
+ q->red*Da,Da);
+ composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
+ q->green*Da,Da);
+ composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
+ q->blue*Da,Da);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=gamma*Multiply(QuantumScale*p->index*Sa,Sa,QuantumScale*
+ q->index*Da,Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange*(1.0-Sa*Da);
+ if ( (channel & RedChannel) != 0 )
+ composite->red=QuantumScale*p->red*q->red;
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=QuantumScale*p->green*q->green;
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=QuantumScale*p->blue*q->blue;
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=QuantumScale*p->index*q->index;
+ }
}
static inline MagickRealType Out(const MagickRealType p,
- const MagickRealType alpha,const MagickRealType magick_unused(q),
- const MagickRealType beta)
+ const MagickRealType Sa,const MagickRealType magick_unused(q),
+ const MagickRealType Da)
{
- return((1.0-QuantumScale*alpha)*p*QuantumScale*beta);
+ return(Sa*p*(1.0-Da));
}
static inline void CompositeOut(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
+ Sa,
+ Da,
gamma;
- gamma=(1.0-QuantumScale*alpha)*QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ gamma=Sa*(1.0-Da);
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Out(p->red,alpha,q->red,beta);
- composite->green=gamma*Out(p->green,alpha,q->green,beta);
- composite->blue=gamma*Out(p->blue,alpha,q->blue,beta);
+ composite->red=gamma*Out(p->red,Sa,q->red,Da);
+ composite->green=gamma*Out(p->green,Sa,q->green,Da);
+ composite->blue=gamma*Out(p->blue,Sa,q->blue,Da);
if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Out(p->index,alpha,q->index,beta);
-}
-
-static inline void CompositeOver(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
-{
- MagickPixelCompositeOver(p,alpha,q,beta,composite);
+ composite->index=gamma*Out(p->index,Sa,q->index,Da);
}
static MagickRealType PegtopLight(const MagickRealType Sca,
const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
{
/*
- PegTOP Soft-Light alternative: A continuous version of the Softlight
- function, producing very similar results however it does not take into
- account alpha channel.
+ PegTop: A Soft-Light alternative: A continuous version of the Softlight
+ function, producing very similar results.
f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
}
static inline void CompositePegtopLight(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
}
static inline void CompositePinLight(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
q->index*Da,Da);
}
-static inline void CompositePlus(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
-{
- MagickPixelCompositePlus(p,alpha,q,beta,composite);
-}
-
static inline MagickRealType Screen(const MagickRealType Sca,
const MagickRealType Dca)
{
+ /* Screen: A negated multiply
+ f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
+ */
return(Sca+Dca-Sca*Dca);
}
static inline void CompositeScreen(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,const ChannelType channel,
+ MagickPixelPacket *composite)
{
MagickRealType
+ Sa,
Da,
- gamma,
- Sa;
+ gamma;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
- gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
- composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
- composite->red=gamma*Screen(QuantumScale*p->red*Sa,QuantumScale*
- q->red*Da);
- composite->green=gamma*Screen(QuantumScale*p->green*Sa,QuantumScale*
- q->green*Da);
- composite->blue=gamma*Screen(QuantumScale*p->blue*Sa,QuantumScale*
- q->blue*Da);
- if (q->colorspace == CMYKColorspace)
- composite->index=gamma*Screen(QuantumScale*p->index*Sa,QuantumScale*
- q->index*Da);
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
+ if ( (channel & SyncChannels) != 0 ) {
+ gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
+ composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
+ Sa*=QuantumScale; Da*=QuantumScale; /* optimization */
+ gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
+ composite->red=gamma*Screen(p->red*Sa,q->red*Da);
+ composite->green=gamma*Screen(p->green*Sa,q->green*Da);
+ composite->blue=gamma*Screen(p->blue*Sa,q->blue*Da);
+ if (q->colorspace == CMYKColorspace)
+ composite->index=gamma*Screen(p->index*Sa,q->index*Da);
+ }
+ else { /* handle channels as separate grayscale channels */
+ if ( (channel & AlphaChannel) != 0 )
+ composite->opacity=QuantumRange*(1.0-Screen(Sa,Da));
+ if ( (channel & RedChannel) != 0 )
+ composite->red=QuantumRange*Screen(QuantumScale*p->red,
+ QuantumScale*q->red);
+ if ( (channel & GreenChannel) != 0 )
+ composite->green=QuantumRange*Screen(QuantumScale*p->green,
+ QuantumScale*q->green);
+ if ( (channel & BlueChannel) != 0 )
+ composite->blue=QuantumRange*Screen(QuantumScale*p->blue,
+ QuantumScale*q->blue);
+ if ( (channel & IndexChannel) != 0 && q->colorspace == CMYKColorspace)
+ composite->index=QuantumRange*Screen(QuantumScale*p->index,
+ QuantumScale*q->index);
+ }
}
static MagickRealType SoftLight(const MagickRealType Sca,
{
#if 0
/*
- Oct 2004 SVG specification -- spec discovered to be incorrect
+ Oct 2004 SVG specification -- was found to be incorrect
See http://lists.w3.org/Archives/Public/www-svg/2009Feb/0014.html.
*/
if (2.0*Sca < Sa)
}
static inline void CompositeSoftLight(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
q->index*Da,Da);
}
-static inline MagickRealType Subtract(const MagickRealType p,
- const MagickRealType magick_unused(alpha),const MagickRealType q,
- const MagickRealType magick_unused(beta))
-{
- MagickRealType
- pixel;
-
- pixel=p-q;
- if (pixel < 0.0)
- pixel+=(QuantumRange+1.0);
- return(pixel);
-}
-
-static inline void CompositeSubtract(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
-{
- composite->red=Subtract(p->red,alpha,q->red,beta);
- composite->green=Subtract(p->green,alpha,q->green,beta);
- composite->blue=Subtract(p->blue,alpha,q->blue,beta);
- if (q->colorspace == CMYKColorspace)
- composite->index=Subtract(p->index,alpha,q->index,beta);
-}
-
+/*
+ Depreciated
+ Multiply difference by amount, if differance larger than threshold???
+ What use this is is completely unknown
+ The Opacity calculation appears to be inverted -- Anthony Thyssen
+*/
static inline MagickRealType Threshold(const MagickRealType p,
- const MagickRealType magick_unused(alpha),const MagickRealType q,
- const MagickRealType magick_unused(beta),const MagickRealType threshold,
+ const MagickRealType q,const MagickRealType threshold,
const MagickRealType amount)
{
MagickRealType
}
static inline void CompositeThreshold(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,const MagickRealType threshold,
+ const MagickPixelPacket *q,const MagickRealType threshold,
const MagickRealType amount,MagickPixelPacket *composite)
{
- composite->red=Threshold(p->red,alpha,q->red,beta,threshold,amount);
- composite->green=Threshold(p->green,alpha,q->green,beta,threshold,amount);
- composite->blue=Threshold(p->blue,alpha,q->blue,beta,threshold,amount);
- composite->opacity=(MagickRealType) QuantumRange-
- Threshold(p->opacity,alpha,q->opacity,beta,threshold,amount);
+ composite->red=Threshold(p->red,q->red,threshold,amount);
+ composite->green=Threshold(p->green,q->green,threshold,amount);
+ composite->blue=Threshold(p->blue,q->blue,threshold,amount);
+ composite->opacity=QuantumRange-Threshold(p->opacity,q->opacity,
+ threshold,amount);
if (q->colorspace == CMYKColorspace)
- composite->index=Threshold(p->index,alpha,q->index,beta,threshold,amount);
+ composite->index=Threshold(p->index,q->index,threshold,amount);
}
+
static MagickRealType VividLight(const MagickRealType Sca,
const MagickRealType Sa, const MagickRealType Dca, const MagickRealType Da)
{
}
static inline void CompositeVividLight(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
}
static inline void CompositeXor(const MagickPixelPacket *p,
- const MagickRealType alpha,const MagickPixelPacket *q,
- const MagickRealType beta,MagickPixelPacket *composite)
+ const MagickPixelPacket *q,MagickPixelPacket *composite)
{
MagickRealType
Da,
gamma,
Sa;
- Sa=1.0-QuantumScale*alpha; /* simplify and speed up equations */
- Da=1.0-QuantumScale*beta;
+ Sa=1.0-QuantumScale*p->opacity; /* simplify and speed up equations */
+ Da=1.0-QuantumScale*q->opacity;
gamma=Sa+Da-2*Sa*Da; /* Xor blend mode X=0,Y=1,Z=1 */
composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
- /*
- Optimized by multipling QuantumRange taken from gamma.
- */
gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
composite->red=gamma*Xor(p->red*Sa,Sa,q->red*Da,Da);
composite->green=gamma*Xor(p->green*Sa,Sa,q->green*Da,Da);
MagickExport MagickBooleanType CompositeImage(Image *image,
const CompositeOperator compose,const Image *composite_image,
- const long x_offset,const long y_offset)
+ const ssize_t x_offset,const ssize_t y_offset)
{
MagickBooleanType
status;
}
MagickExport MagickBooleanType CompositeImageChannel(Image *image,
- const ChannelType magick_unused(channel),const CompositeOperator compose,
- const Image *composite_image,const long x_offset,const long y_offset)
+ const ChannelType channel,const CompositeOperator compose,
+ const Image *composite_image,const ssize_t x_offset,const ssize_t y_offset)
{
#define CompositeImageTag "Composite/Image"
Image
*destination_image;
- long
- progress,
- y;
-
MagickBooleanType
modify_outside_overlay,
status;
+ MagickOffsetType
+ progress;
+
MagickPixelPacket
zero;
MagickStatusType
flags;
+ ssize_t
+ y;
+
/*
Prepare composite image.
*/
{
if ((x_offset < 0) || (y_offset < 0))
break;
- if ((x_offset+(long) composite_image->columns) >= (long) image->columns)
+ if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
break;
- if ((y_offset+(long) composite_image->rows) >= (long) image->rows)
+ if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
break;
status=MagickTrue;
exception=(&image->exception);
image_view=AcquireCacheView(image);
composite_view=AcquireCacheView(composite_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
-#pragma omp parallel for shared(status)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
- for (y=0; y < (long) composite_image->rows; y++)
+ for (y=0; y < (ssize_t) composite_image->rows; y++)
{
MagickBooleanType
sync;
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
-#pragma omp critical (MagickCore_TextureImage)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+#pragma omp critical (MagickCore_CompositeImage)
#endif
- proceed=SetImageProgress(image,CompositeImageTag,y,image->rows);
+ proceed=SetImageProgress(image,CompositeImageTag,
+ (MagickOffsetType) y,image->rows);
if (proceed == MagickFalse)
status=MagickFalse;
}
}
case BlurCompositeOp:
{
+ CacheView
+ *composite_view,
+ *destination_view;
+
MagickPixelPacket
pixel;
MagickRealType
- blur_xu,
- blur_xv,
- blur_yu,
- blur_yv;
+ angle_range,
+ angle_start,
+ height,
+ width;
ResampleFilter
*resample_filter;
- CacheView
- *composite_view,
- *dest_view;
+ SegmentInfo
+ blur;
/*
- Blur Image dictated by an overlay gradient map:
- X = red_channel; Y = green_channel;
- compose:args = x_scale[,y_scale[,angle]]
+ Blur Image dictated by an overlay gradient map: X = red_channel;
+ Y = green_channel; compose:args = x_scale[,y_scale[,angle]].
*/
destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
&image->exception);
destination_image=DestroyImage(destination_image);
return(MagickFalse);
}
- blur_xu=geometry_info.rho;
- blur_yv=geometry_info.sigma;
- blur_xv=blur_yu = 0.0;
+ width=geometry_info.rho;
+ height=geometry_info.sigma;
+ blur.x1=geometry_info.rho;
+ blur.x2=0.0;
+ blur.y1=0.0;
+ blur.y2=geometry_info.sigma;
+ angle_start=0.0;
+ angle_range=0.0;
if ((flags & HeightValue) == 0)
- blur_yv=blur_xu;
- if ((flags & XValue) != 0)
+ blur.y2=blur.x1;
+ if ((flags & XValue) != 0 )
{
MagickRealType
- angle,
- x,
- y;
+ angle;
- x=blur_xu;
- y=blur_yv;
angle=DegreesToRadians(geometry_info.xi);
- blur_xu=x*cos(angle);
- blur_xv=x*sin(angle);
- blur_yu=(-y*sin(angle));
- blur_yu=y*cos(angle);
+ blur.x1=width*cos(angle);
+ blur.x2=width*sin(angle);
+ blur.y1=(-height*sin(angle));
+ blur.y2=height*cos(angle);
+ }
+ if ((flags & YValue) != 0 )
+ {
+ angle_start=DegreesToRadians(geometry_info.xi);
+ angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
}
/*
Blur Image by resampling;
pixel=zero;
exception=(&image->exception);
resample_filter=AcquireResampleFilter(image,&image->exception);
- SetResampleFilter(resample_filter,GaussianFilter,1.0);
- dest_view=AcquireCacheView(destination_image);
+ SetResampleFilter(resample_filter,GaussianFilter,sqrt(2.0));
+ destination_view=AcquireCacheView(destination_image);
composite_view=AcquireCacheView(composite_image);
- for (y=0; y < (long) composite_image->rows; y++)
+ for (y=0; y < (ssize_t) composite_image->rows; y++)
{
MagickBooleanType
sync;
register const PixelPacket
- *__restrict p;
+ *restrict p;
register PixelPacket
- *__restrict r;
+ *restrict r;
register IndexPacket
- *__restrict destination_indexes;
+ *restrict destination_indexes;
- register long
+ register ssize_t
x;
- if (((y+y_offset) < 0) || ((y+y_offset) >= (long) image->rows))
+ if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
continue;
p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1,exception);
- r=QueueCacheViewAuthenticPixels(dest_view,0,y,
+ r=QueueCacheViewAuthenticPixels(destination_view,0,y,
destination_image->columns,1,&image->exception);
if ((p == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
break;
- destination_indexes=GetCacheViewAuthenticIndexQueue(dest_view);
- for (x=0; x < (long) composite_image->columns; x++)
+ destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
+ for (x=0; x < (ssize_t) composite_image->columns; x++)
{
- if (((x_offset+x) < 0) || ((x_offset+x) >= (long) image->columns))
+ if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
{
p++;
continue;
}
- ScaleResampleFilter(resample_filter,blur_xu*QuantumScale*p->red,
- blur_yu*QuantumScale*p->green,blur_xv*QuantumScale*p->red,
- blur_yv*QuantumScale*p->green);
+ if (fabs(angle_range) > MagickEpsilon)
+ {
+ MagickRealType
+ angle;
+
+ angle=angle_start+angle_range*QuantumScale*
+ GetBluePixelComponent(p);
+ blur.x1=width*cos(angle);
+ blur.x2=width*sin(angle);
+ blur.y1=(-height*sin(angle));
+ blur.y2=height*cos(angle);
+ }
+ ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*p->red,
+ blur.y1*QuantumScale*p->green,blur.x2*QuantumScale*p->red,
+ blur.y2*QuantumScale*GetGreenPixelComponent(p));
(void) ResamplePixelColor(resample_filter,(double) x_offset+x,
(double) y_offset+y,&pixel);
SetPixelPacket(destination_image,&pixel,r,destination_indexes+x);
p++;
r++;
}
- sync=SyncCacheViewAuthenticPixels(dest_view,exception);
+ sync=SyncCacheViewAuthenticPixels(destination_view,exception);
if (sync == MagickFalse)
break;
}
resample_filter=DestroyResampleFilter(resample_filter);
composite_view=DestroyCacheView(composite_view);
- dest_view=DestroyCacheView(dest_view);
+ destination_view=DestroyCacheView(destination_view);
composite_image=destination_image;
break;
}
case DisplaceCompositeOp:
case DistortCompositeOp:
{
+ CacheView
+ *composite_view,
+ *destination_view;
+
MagickPixelPacket
pixel;
MagickRealType
horizontal_scale,
- vertical_scale,
- x_center,
- y_center,
- x_lookup,
- y_lookup;
+ vertical_scale;
+
+ PointInfo
+ center,
+ offset;
register IndexPacket
- *__restrict destination_indexes;
+ *restrict destination_indexes;
register PixelPacket
- *__restrict r;
+ *restrict r;
ResampleFilter
*resample_filter;
- CacheView
- *composite_view,
- *dest_view;
-
/*
Displace/Distort based on overlay gradient map:
X = red_channel; Y = green_channel;
- compose:args = x_scale[,y_scale[,x_center,y_center]]
+ compose:args = x_scale[,y_scale[,center.x,center.y]]
*/
destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
&image->exception);
if (value != (char *) NULL)
flags=ParseGeometry(value,&geometry_info);
if ((flags & (WidthValue|HeightValue)) == 0 )
- if ((flags & AspectValue) == 0)
- {
- horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
- 2.0;
- vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
- }
- else
- {
- horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
- vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
- }
+ {
+ if ((flags & AspectValue) == 0)
+ {
+ horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
+ 2.0;
+ vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
+ }
+ else
+ {
+ horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
+ vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
+ }
+ }
else
{
horizontal_scale=geometry_info.rho;
/*
Determine fixed center point for absolute distortion map
Absolute distort ==
- Displace lookup relative to a fixed absolute point
+ Displace offset relative to a fixed absolute point
Select that point according to +X+Y user inputs.
default = center of overlay image
- flag '!' = locations/percentage relative to background image
+ arg flag '!' = locations/percentage relative to background image
*/
- x_center=(MagickRealType) x_offset;
- y_center=(MagickRealType) y_offset;
+ center.x=(MagickRealType) x_offset;
+ center.y=(MagickRealType) y_offset;
if (compose == DistortCompositeOp)
{
if ((flags & XValue) == 0)
if ((flags & AspectValue) == 0)
- x_center=(MagickRealType) x_offset+ (composite_image->columns-1)/
+ center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
2.0;
else
- x_center=((MagickRealType) image->columns-1)/2.0;
+ center.x=((MagickRealType) image->columns-1)/2.0;
else
if ((flags & AspectValue) == 0)
- x_center=(MagickRealType) x_offset+geometry_info.xi;
+ center.x=(MagickRealType) x_offset+geometry_info.xi;
else
- x_center=geometry_info.xi;
+ center.x=geometry_info.xi;
if ((flags & YValue) == 0)
if ((flags & AspectValue) == 0)
- y_center=(MagickRealType) y_offset+
- (composite_image->rows-1)/2.0;
+ center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
else
- y_center=((MagickRealType) image->rows-1)/2.0;
+ center.y=((MagickRealType) image->rows-1)/2.0;
else
if ((flags & AspectValue) == 0)
- y_center=(MagickRealType) y_offset+geometry_info.psi;
+ center.y=(MagickRealType) y_offset+geometry_info.psi;
else
- y_center=geometry_info.psi;
+ center.y=geometry_info.psi;
}
/*
- Shift the pixel lookup point as defined by the provided,
+ Shift the pixel offset point as defined by the provided,
displacement/distortion map. -- Like a lens...
*/
pixel=zero;
exception=(&image->exception);
resample_filter=AcquireResampleFilter(image,&image->exception);
- dest_view=AcquireCacheView(destination_image);
+ destination_view=AcquireCacheView(destination_image);
composite_view=AcquireCacheView(composite_image);
- for (y=0; y < (long) composite_image->rows; y++)
+ for (y=0; y < (ssize_t) composite_image->rows; y++)
{
MagickBooleanType
sync;
register const PixelPacket
- *__restrict p;
+ *restrict p;
- register long
+ register ssize_t
x;
- if (((y+y_offset) < 0) || ((y+y_offset) >= (long) image->rows))
+ if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
continue;
p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1,exception);
- r=QueueCacheViewAuthenticPixels(dest_view,0,y,
+ r=QueueCacheViewAuthenticPixels(destination_view,0,y,
destination_image->columns,1,&image->exception);
if ((p == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
break;
- destination_indexes=GetCacheViewAuthenticIndexQueue(dest_view);
- for (x=0; x < (long) composite_image->columns; x++)
+ destination_indexes=GetCacheViewAuthenticIndexQueue(destination_view);
+ for (x=0; x < (ssize_t) composite_image->columns; x++)
{
- if (((x_offset+x) < 0) || ((x_offset+x) >= (long) image->columns))
+ if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
{
p++;
continue;
}
/*
- Displace the lookup.
+ Displace the offset.
*/
- x_lookup=(horizontal_scale*(p->red-(((MagickRealType) QuantumRange+
+ offset.x=(horizontal_scale*(p->red-(((MagickRealType) QuantumRange+
1.0)/2.0)))/(((MagickRealType) QuantumRange+1.0)/2.0)+
- x_center+((compose == DisplaceCompositeOp) ? x : 0);
- y_lookup=(vertical_scale*(p->green-(((MagickRealType) QuantumRange+
+ center.x+((compose == DisplaceCompositeOp) ? x : 0);
+ offset.y=(vertical_scale*(p->green-(((MagickRealType) QuantumRange+
1.0)/2.0)))/(((MagickRealType) QuantumRange+1.0)/2.0)+
- y_center+((compose == DisplaceCompositeOp) ? y : 0);
- (void) ResamplePixelColor(resample_filter,(double) x_lookup,
- (double) y_lookup,&pixel);
+ center.y+((compose == DisplaceCompositeOp) ? y : 0);
+ (void) ResamplePixelColor(resample_filter,(double) offset.x,
+ (double) offset.y,&pixel);
/*
- Mask with 'invalid pixel mask' in alpha channel.
+ Mask with the 'invalid pixel mask' in alpha channel.
*/
- pixel.opacity = (MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
- pixel.opacity)*(1.0-QuantumScale*p->opacity));
+ pixel.opacity=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
+ pixel.opacity)*(1.0-QuantumScale*GetOpacityPixelComponent(p)));
SetPixelPacket(destination_image,&pixel,r,destination_indexes+x);
p++;
r++;
}
- sync=SyncCacheViewAuthenticPixels(dest_view,exception);
+ sync=SyncCacheViewAuthenticPixels(destination_view,exception);
if (sync == MagickFalse)
break;
}
resample_filter=DestroyResampleFilter(resample_filter);
composite_view=DestroyCacheView(composite_view);
- dest_view=DestroyCacheView(dest_view);
+ destination_view=DestroyCacheView(destination_view);
composite_image=destination_image;
break;
}
{
/*
Determine the amount and threshold.
+ This Composition method is depreciated
*/
value=GetImageArtifact(composite_image,"compose:args");
if (value != (char *) NULL)
exception=(&image->exception);
image_view=AcquireCacheView(image);
composite_view=AcquireCacheView(composite_image);
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
- #pragma omp parallel for shared(progress,status)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
- for (y=0; y < (long) image->rows; y++)
+ for (y=0; y < (ssize_t) image->rows; y++)
{
const PixelPacket
*pixels;
source;
register const IndexPacket
- *__restrict composite_indexes;
+ *restrict composite_indexes;
register const PixelPacket
- *__restrict p;
+ *restrict p;
register IndexPacket
- *__restrict indexes;
+ *restrict indexes;
- register long
+ register ssize_t
x;
register PixelPacket
- *__restrict q;
+ *restrict q;
if (status == MagickFalse)
continue;
{
if (y < y_offset)
continue;
- if ((y-y_offset) >= (long) composite_image->rows)
+ if ((y-y_offset) >= (ssize_t) composite_image->rows)
continue;
}
/*
*/
pixels=(PixelPacket *) NULL;
p=(PixelPacket *) NULL;
- if ((y >= y_offset) && ((y-y_offset) < (long) composite_image->rows))
+ if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
{
p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
composite_image->columns,1,exception);
hue=0.0;
saturation=0.0;
brightness=0.0;
- for (x=0; x < (long) image->columns; x++)
+ for (x=0; x < (ssize_t) image->columns; x++)
{
if (modify_outside_overlay == MagickFalse)
{
q++;
continue;
}
- if ((x-x_offset) >= (long) composite_image->columns)
+ if ((x-x_offset) >= (ssize_t) composite_image->columns)
break;
}
destination.red=(MagickRealType) q->red;
*/
composite=destination;
if ((pixels == (PixelPacket *) NULL) || (x < x_offset) ||
- ((x-x_offset) >= (long) composite_image->columns))
+ ((x-x_offset) >= (ssize_t) composite_image->columns))
{
switch (compose)
{
composite.blue=(MagickRealType) QuantumRange-composite.blue;
composite.index=(MagickRealType) QuantumRange-composite.index;
}
- q->red=RoundToQuantum(composite.red);
- q->green=RoundToQuantum(composite.green);
- q->blue=RoundToQuantum(composite.blue);
+ q->red=ClampToQuantum(composite.red);
+ q->green=ClampToQuantum(composite.green);
+ q->blue=ClampToQuantum(composite.blue);
if (image->matte != MagickFalse)
- q->opacity=RoundToQuantum(composite.opacity);
+ q->opacity=ClampToQuantum(composite.opacity);
if (image->colorspace == CMYKColorspace)
- indexes[x]=RoundToQuantum(composite.index);
+ indexes[x]=ClampToQuantum(composite.index);
q++;
continue;
}
/*
Handle normal overlay of source onto destination.
*/
- source.red=(MagickRealType) p->red;
- source.green=(MagickRealType) p->green;
- source.blue=(MagickRealType) p->blue;
+ source.red=(MagickRealType) GetRedPixelComponent(p);
+ source.green=(MagickRealType) GetGreenPixelComponent(p);
+ source.blue=(MagickRealType) GetBluePixelComponent(p);
if (composite_image->matte != MagickFalse)
- source.opacity=(MagickRealType) p->opacity;
+ source.opacity=(MagickRealType) GetOpacityPixelComponent(p);
if (composite_image->colorspace == CMYKColorspace)
{
source.red=(MagickRealType) QuantumRange-source.red;
}
switch (compose)
{
- case AddCompositeOp:
- {
- CompositeAdd(&source,source.opacity,&destination,destination.opacity,
- &composite);
- break;
- }
+ /* Duff-Porter Compositions */
case ClearCompositeOp:
{
CompositeClear(&destination,&composite);
composite=source;
break;
}
- case ChangeMaskCompositeOp:
- {
- if ((composite.opacity > ((MagickRealType) QuantumRange/2.0)) ||
- (IsMagickColorSimilar(&source,&destination) != MagickFalse))
- composite.opacity=(MagickRealType) TransparentOpacity;
- else
- composite.opacity=(MagickRealType) OpaqueOpacity;
- break;
- }
- case DivideCompositeOp:
- {
- CompositeDivide(&source,source.opacity,&destination,
- destination.opacity,&composite);
- break;
- }
+ case NoCompositeOp:
case DstCompositeOp:
break;
case OverCompositeOp:
case SrcOverCompositeOp:
{
- CompositeOver(&source,source.opacity,&destination,destination.opacity,
- &composite);
+ MagickPixelCompositeOver(&source,source.opacity,
+ &destination,destination.opacity,&composite);
break;
}
case DstOverCompositeOp:
{
- CompositeOver(&destination,destination.opacity,&source,source.opacity,
- &composite);
+ MagickPixelCompositeOver(&destination,destination.opacity,
+ &source,source.opacity,&composite);
break;
}
case SrcInCompositeOp:
case InCompositeOp:
{
- CompositeIn(&source,source.opacity,&destination,destination.opacity,
- &composite);
+ CompositeIn(&source,&destination,&composite);
break;
}
case DstInCompositeOp:
{
- CompositeIn(&destination,destination.opacity,&source,source.opacity,
- &composite);
+ CompositeIn(&destination,&source,&composite);
break;
}
case OutCompositeOp:
case SrcOutCompositeOp:
{
- CompositeOut(&source,source.opacity,&destination,destination.opacity,
- &composite);
+ CompositeOut(&source,&destination,&composite);
break;
}
case DstOutCompositeOp:
{
- CompositeOut(&destination,destination.opacity,&source,source.opacity,
- &composite);
+ CompositeOut(&destination,&source,&composite);
break;
}
case AtopCompositeOp:
case SrcAtopCompositeOp:
{
- CompositeAtop(&source,source.opacity,&destination,destination.opacity,
- &composite);
+ CompositeAtop(&source,&destination,&composite);
break;
}
case DstAtopCompositeOp:
{
- CompositeAtop(&destination,destination.opacity,&source,source.opacity,
- &composite);
+ CompositeAtop(&destination,&source,&composite);
break;
}
case XorCompositeOp:
{
- CompositeXor(&source,source.opacity,&destination,destination.opacity,
- &composite);
+ CompositeXor(&source,&destination,&composite);
break;
}
+ /* Mathematical Compositions */
case PlusCompositeOp:
{
- CompositePlus(&source,source.opacity,&destination,destination.opacity,
- &composite);
+ CompositePlus(&source,&destination,channel,&composite);
+ break;
+ }
+ case MinusCompositeOp:
+ {
+ CompositeMinus(&source,&destination,
+ channel,&composite);
+ break;
+ }
+ case ModulusAddCompositeOp:
+ {
+ CompositeModulusAdd(&source,&destination,channel,&composite);
+ break;
+ }
+ case ModulusSubtractCompositeOp:
+ {
+ CompositeModulusSubtract(&source,&destination,channel,&composite);
+ break;
+ }
+ case DifferenceCompositeOp:
+ {
+ CompositeDifference(&source,&destination,channel,&composite);
+ break;
+ }
+ case ExclusionCompositeOp:
+ {
+ CompositeExclusion(&source,&destination,channel,&composite);
break;
}
case MultiplyCompositeOp:
{
- CompositeMultiply(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeMultiply(&source,&destination,channel,&composite);
break;
}
case ScreenCompositeOp:
{
- CompositeScreen(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeScreen(&source,&destination,channel,&composite);
+ break;
+ }
+ case DivideCompositeOp:
+ {
+ CompositeDivide(&source,&destination,channel,&composite);
break;
}
case DarkenCompositeOp:
{
- CompositeDarken(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeDarken(&source,&destination,channel,&composite);
break;
}
case LightenCompositeOp:
{
- CompositeLighten(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeLighten(&source,&destination,channel,&composite);
break;
}
+ case MathematicsCompositeOp:
+ {
+ CompositeMathematics(&source,&destination,channel,&geometry_info,
+ &composite);
+ break;
+ }
+ /* Lighting Compositions */
case ColorDodgeCompositeOp:
{
- CompositeColorDodge(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeColorDodge(&source,&destination,&composite);
break;
}
case ColorBurnCompositeOp:
{
- CompositeColorBurn(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeColorBurn(&source,&destination,&composite);
break;
}
case LinearDodgeCompositeOp:
{
- CompositeLinearDodge(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeLinearDodge(&source,&destination,&composite);
break;
}
case LinearBurnCompositeOp:
{
- CompositeLinearBurn(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeLinearBurn(&source,&destination,&composite);
break;
}
case HardLightCompositeOp:
{
- CompositeHardLight(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeHardLight(&source,&destination,&composite);
break;
}
case OverlayCompositeOp:
{
- /*
- Reversed HardLight.
- */
- CompositeHardLight(&destination,destination.opacity,&source,
- source.opacity,&composite);
+ /* Overlay = Reversed HardLight. */
+ CompositeHardLight(&destination,&source,&composite);
break;
}
case SoftLightCompositeOp:
{
- CompositeSoftLight(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeSoftLight(&source,&destination,&composite);
break;
}
case LinearLightCompositeOp:
{
- CompositeLinearLight(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeLinearLight(&source,&destination,&composite);
break;
}
case PegtopLightCompositeOp:
{
- CompositePegtopLight(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositePegtopLight(&source,&destination,&composite);
break;
}
case VividLightCompositeOp:
{
- CompositeVividLight(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeVividLight(&source,&destination,&composite);
break;
}
case PinLightCompositeOp:
{
- CompositePinLight(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositePinLight(&source,&destination,&composite);
break;
}
- case DifferenceCompositeOp:
- {
- CompositeDifference(&source,source.opacity,&destination,
- destination.opacity,&composite);
- break;
- }
- case ExclusionCompositeOp:
- {
- CompositeExclusion(&source,source.opacity,&destination,
- destination.opacity,&composite);
- break;
- }
- case MinusCompositeOp:
+ /* Other Composition */
+ case ChangeMaskCompositeOp:
{
- CompositeMinus(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ if ((composite.opacity > ((MagickRealType) QuantumRange/2.0)) ||
+ (IsMagickColorSimilar(&source,&destination) != MagickFalse))
+ composite.opacity=(MagickRealType) TransparentOpacity;
+ else
+ composite.opacity=(MagickRealType) OpaqueOpacity;
break;
}
case BumpmapCompositeOp:
{
if (source.opacity == TransparentOpacity)
break;
- CompositeBumpmap(&source,source.opacity,&destination,
- destination.opacity,&composite);
+ CompositeBumpmap(&source,&destination,&composite);
break;
}
case DissolveCompositeOp:
{
- CompositeOver(&source,(MagickRealType) (QuantumRange-source_dissolve*
+ MagickPixelCompositeOver(&source,(MagickRealType) (QuantumRange-source_dissolve*
(QuantumRange-source.opacity)),&destination,(MagickRealType)
(QuantumRange-destination_dissolve*(QuantumRange-
destination.opacity)),&composite);
destination_dissolve,&composite);
break;
}
- case MathematicsCompositeOp:
- {
- CompositeMathematics(&source,&destination,&geometry_info,&composite);
- break;
- }
- case BlurCompositeOp:
- case DisplaceCompositeOp:
- case DistortCompositeOp:
- {
- composite=source;
- break;
- }
case ThresholdCompositeOp:
{
- CompositeThreshold(&source,source.opacity,&destination,
- destination.opacity,threshold,amount,&composite);
+ CompositeThreshold(&source,&destination,threshold,amount,&composite);
break;
}
case ModulateCompositeOp:
{
- long
+ ssize_t
offset;
if (source.opacity == TransparentOpacity)
break;
- offset=(long) (MagickPixelIntensityToQuantum(&source)-midpoint);
+ offset=(ssize_t) (MagickPixelIntensityToQuantum(&source)-midpoint);
if (offset == 0)
break;
CompositeHSB(destination.red,destination.green,destination.blue,&hue,
composite.opacity=source.opacity;
break;
}
- case SubtractCompositeOp:
- {
- CompositeSubtract(&source,source.opacity,&destination,
- destination.opacity,&composite);
- break;
- }
case LuminizeCompositeOp:
{
if (source.opacity == TransparentOpacity)
composite.index=source.index;
break;
}
+ /* compose methods that are already handled */
+ case BlurCompositeOp:
+ case DisplaceCompositeOp:
+ case DistortCompositeOp:
+ {
+ composite=source;
+ break;
+ }
default:
break;
}
composite.blue=(MagickRealType) QuantumRange-composite.blue;
composite.index=(MagickRealType) QuantumRange-composite.index;
}
- q->red=RoundToQuantum(composite.red);
- q->green=RoundToQuantum(composite.green);
- q->blue=RoundToQuantum(composite.blue);
- q->opacity=RoundToQuantum(composite.opacity);
+ q->red=ClampToQuantum(composite.red);
+ q->green=ClampToQuantum(composite.green);
+ q->blue=ClampToQuantum(composite.blue);
+ q->opacity=ClampToQuantum(composite.opacity);
if (image->colorspace == CMYKColorspace)
- indexes[x]=RoundToQuantum(composite.index);
+ indexes[x]=ClampToQuantum(composite.index);
p++;
if (p >= (pixels+composite_image->columns))
p=pixels;
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp critical (MagickCore_CompositeImageChannel)
#endif
proceed=SetImageProgress(image,CompositeImageTag,progress++,
ExceptionInfo
*exception;
- long
+ ssize_t
y;
MagickBooleanType
assert(image->signature == MagickSignature);
if (texture == (const Image *) NULL)
return(MagickFalse);
+ (void) SetImageVirtualPixelMethod(texture,TileVirtualPixelMethod);
if (SetImageStorageClass(image,DirectClass) == MagickFalse)
return(MagickFalse);
status=MagickTrue;
/*
Tile texture onto the image background.
*/
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
- #pragma omp parallel for shared(status)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
#endif
- for (y=0; y < (long) image->rows; y+=texture->rows)
+ for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture->rows)
{
- register long
+ register ssize_t
x;
if (status == MagickFalse)
continue;
- for (x=0; x < (long) image->columns; x+=texture->columns)
+ for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
{
MagickBooleanType
thread_status;
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
#pragma omp critical (MagickCore_TextureImage)
#endif
- proceed=SetImageProgress(image,TextureImageTag,y,image->rows);
+ proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
+ y,image->rows);
if (proceed == MagickFalse)
status=MagickFalse;
}
exception=(&image->exception);
image_view=AcquireCacheView(image);
texture_view=AcquireCacheView(texture);
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
-#pragma omp parallel for shared(status)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
#endif
- for (y=0; y < (long) image->rows; y++)
+ for (y=0; y < (ssize_t) image->rows; y++)
{
MagickBooleanType
sync;
register IndexPacket
*indexes;
- register long
+ register ssize_t
x;
register PixelPacket
*q;
- unsigned long
+ size_t
width;
if (status == MagickFalse)
continue;
- p=GetCacheViewVirtualPixels(texture_view,0,y % texture->rows,
- texture->columns,1,exception);
+ p=GetCacheViewVirtualPixels(texture_view,texture->tile_offset.x,(y+
+ texture->tile_offset.y) % texture->rows,texture->columns,1,exception);
q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
exception);
if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
}
texture_indexes=GetCacheViewVirtualIndexQueue(texture_view);
indexes=GetCacheViewAuthenticIndexQueue(image_view);
- for (x=0; x < (long) image->columns; x+=texture->columns)
+ for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
{
width=texture->columns;
- if ((x+(long) width) > (long) image->columns)
+ if ((x+(ssize_t) width) > (ssize_t) image->columns)
width=image->columns-x;
(void) CopyMagickMemory(q,p,width*sizeof(*p));
if ((image->colorspace == CMYKColorspace) &&
MagickBooleanType
proceed;
-#if defined(MAGICKCORE_OPENMP_SUPPORT) && (_OPENMP >= 200203)
-#pragma omp critical (MagickCore_TextureImage)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_TextureImage)
#endif
- proceed=SetImageProgress(image,TextureImageTag,y,image->rows);
+ proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
+ image->rows);
if (proceed == MagickFalse)
status=MagickFalse;
}