]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/composite.c
(no commit message)
[imagemagick] / MagickCore / composite.c
index 4500683c8f81d2c517f1c81b3808adc29c90d30b..29f3dd7baad19c838ce27c069e3dc94febc817df 100644 (file)
 %
 */
 
-static inline double MagickMin(const double x,const double y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-static inline double MagickMax(const double x,const double y)
-{
-  if (x > y)
-    return(x);
-  return(y);
-}
-
-/*
-   Programmers notes on SVG specification.
-
-   A Composition is defined by...
-     Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
-      Blending areas :  X = 1    for area of overlap   ie: f(Sc,Dc)
-                        Y = 1    for source preserved
-                        Z = 1    for destination preserved
-
-   Conversion to transparency (then optimized)
-      Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
-      Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
-
-   Where...
-     Sca = Sc*Sa     normalized Source color divided by Source alpha
-     Dca = Dc*Da     normalized Dest color divided by Dest alpha
-     Dc' = Dca'/Da'  the desired color value for this channel.
-
-   Da' (alpha result) is stored as 'gamma' in the functions.
-
-   The compose functions defined is just simplifications of the above
-   formula on a case by case bases.
-
-
-
-   The above SVG definitions also defines 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 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)
+static void CompositeHSB(const Quantum red,const Quantum green,
+  const Quantum blue,double *hue,double *saturation,double *brightness)
 {
-  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);
-}
+  double
+    delta;
 
-static void CompositeHSB(const MagickRealType red,const MagickRealType green,
-  const MagickRealType blue,double *hue,double *saturation,double *brightness)
-{
-  MagickRealType
-    delta,
+  Quantum
     max,
     min;
 
@@ -629,996 +160,445 @@ static void CompositeHSB(const MagickRealType red,const MagickRealType green,
   *hue=0.0;
   *saturation=0.0;
   *brightness=(double) (QuantumScale*max);
-  if (fabs(max) < MagickEpsilon)
+  if (fabs((double) max) < MagickEpsilon)
     return;
   *saturation=(double) (1.0-min/max);
-  delta=max-min;
+  delta=(MagickRealType) max-min;
   if (fabs(delta) < MagickEpsilon)
     return;
-  if (fabs(red-max) < MagickEpsilon)
+  if (fabs((double) red-max) < MagickEpsilon)
     *hue=(double) ((green-blue)/delta);
   else
-    if (fabs(green-max) < MagickEpsilon)
+    if (fabs((double) green-max) < MagickEpsilon)
       *hue=(double) (2.0+(blue-red)/delta);
     else
-      if (fabs(blue-max) < MagickEpsilon)
+      if (fabs((double) blue-max) < MagickEpsilon)
         *hue=(double) (4.0+(red-green)/delta);
   *hue/=6.0;
   if (*hue < 0.0)
     *hue+=1.0;
 }
 
-#if 0
-static inline MagickRealType In(const MagickRealType p,const MagickRealType Sa,
-  const MagickRealType magick_unused(q),const MagickRealType Da)
-{
-  return(Sa*p*Da);
-}
-#endif
-
-static inline void CompositeIn(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-#if 0
-  MagickRealType
-    gamma,
-    Sa,
-    Da;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=Sa*Da;
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  /* really this just preserves the src or p color as is! */
-  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->black=gamma*In(p->black,Sa,q->black,Da);
-#else
-  /* Simplified to a multiply of the Alpha Channel */
-  *composite=*p; /* structure copy */
-  composite->alpha=QuantumScale*p->alpha*q->alpha;
-#endif
-}
-
-static inline MagickRealType Lighten(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 CompositeLighten(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
+static void HSBComposite(const double hue,const double saturation,
+  const double brightness,double *red,double *green,double *blue)
 {
-  MagickRealType
-    gamma;
+  double
+    f,
+    h,
+    p,
+    q,
+    t;
 
   /*
-    Lighten is also equvalent to a 'Maximum' method OR a greyscale version of a
-    binary 'And' OR the 'Union' of pixel sets.
+    Convert HSB to RGB colorspace.
   */
-  if (image->channel_mask != DefaultChannels)
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  if (saturation == 0.0)
     {
-      /*
-        Handle channels as separate grayscale channels
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=MagickMax(p->red,q->red);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=MagickMax(p->green,q->green);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=MagickMax(p->blue,q->blue);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=MagickMax(p->black,q->black);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=MagickMin(p->alpha,q->alpha);
+      *red=(double) QuantumRange*brightness;
+      *green=(*red);
+      *blue=(*red);
       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*Lighten(p->red,p->alpha,q->red,q->alpha);
-  composite->green=gamma*Lighten(p->green,p->alpha,q->green,q->alpha);
-  composite->blue=gamma*Lighten(p->blue,p->alpha,q->blue,q->alpha);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Lighten(p->black,p->alpha,q->black,q->alpha);
-}
-
-static inline void CompositeLightenIntensity(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 Intenisty only, but restrict copy according to channel.
-  */
-  if (image->channel_mask != DefaultChannels)
+  h=6.0*(hue-floor(hue));
+  f=h-floor((double) h);
+  p=brightness*(1.0-saturation);
+  q=brightness*(1.0-saturation*f);
+  t=brightness*(1.0-saturation*(1.0-f));
+  switch ((int) h)
+  {
+    case 0:
+    default:
     {
-      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;
+      *red=(double) QuantumRange*brightness;
+      *green=(double) QuantumRange*t;
+      *blue=(double) QuantumRange*p;
+      break;
     }
-  Sa=QuantumScale*p->alpha;
-  Da=QuantumScale*q->alpha;
-  *composite=(Sa*GetPixelInfoIntensity(p) > Da*GetPixelInfoIntensity(q)) ?
-    *p : *q;
+    case 1:
+    {
+      *red=(double) QuantumRange*q;
+      *green=(double) QuantumRange*brightness;
+      *blue=(double) QuantumRange*p;
+      break;
+    }
+    case 2:
+    {
+      *red=(double) QuantumRange*p;
+      *green=(double) QuantumRange*brightness;
+      *blue=(double) QuantumRange*t;
+      break;
+    }
+    case 3:
+    {
+      *red=(double) QuantumRange*p;
+      *green=(double) QuantumRange*q;
+      *blue=(double) QuantumRange*brightness;
+      break;
+    }
+    case 4:
+    {
+      *red=(double) QuantumRange*t;
+      *green=(double) QuantumRange*p;
+      *blue=(double) QuantumRange*brightness;
+      break;
+    }
+    case 5:
+    {
+      *red=(double) QuantumRange*brightness;
+      *green=(double) QuantumRange*p;
+      *blue=(double) QuantumRange*q;
+      break;
+    }
+  }
 }
 
-static inline void CompositeLinearDodge(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
+static inline double MagickMin(const double x,const double y)
 {
-  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=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);
-  composite->blue=gamma*(p->blue*Sa+q->blue*Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*(p->black*Sa+q->black*Da);
+  if (x < y)
+    return(x);
+  return(y);
 }
-
-
-static inline MagickRealType LinearBurn(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+static inline double MagickMax(const double x,const double y)
 {
-  /*
-    LinearBurn: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
-
-      f(Sc,Dc) = Sc + Dc - 1
-  */
-  return(Sca+Dca-Sa*Da);
+  if (x > y)
+    return(x);
+  return(y);
 }
 
-static inline void CompositeLinearBurn(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
+static MagickBooleanType CompositeOverImage(Image *image,
+  const Image *composite_image,const ssize_t x_offset,const ssize_t y_offset,
+  ExceptionInfo *exception)
 {
-  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*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*LinearBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
+#define CompositeImageTag  "Composite/Image"
 
-static inline MagickRealType LinearLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    LinearLight: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
+  CacheView
+    *composite_view,
+    *image_view;
 
-      f(Sc,Dc) = Dc + 2*Sc - 1
-  */
-  return((Sca-Sa)*Da+Sca+Dca);
-}
+  const char
+    *value;
 
-static inline void CompositeLinearLight(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*LinearLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*LinearLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*LinearLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*LinearLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static inline MagickRealType Mathematics(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
-  const GeometryInfo *geometry_info)
-{
-  MagickRealType
-    gamma;
-
-  /*
-    'Mathematics' a free form user control mathematical composition is defined
-    as...
-
-       f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
-
-    Where the arguments A,B,C,D are (currently) passed to composite as
-    a command separated 'geometry' string in "compose:args" image artifact.
-
-       A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
-
-    Applying the SVG transparency formula (see above), we get...
-
-     Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
+  MagickBooleanType
+    modify_outside_overlay,
+    status;
 
-     Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
-       Dca*(1.0-Sa)
-  */
-  gamma=geometry_info->rho*Sca*Dca+geometry_info->sigma*Sca*Da+
-    geometry_info->xi*Dca*Sa+geometry_info->psi*Sa*Da+Sca*(1.0-Da)+
-    Dca*(1.0-Sa);
-  return(gamma);
-}
+  MagickOffsetType
+    progress;
 
-static inline void CompositeMathematics(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,const GeometryInfo *args,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
+  ssize_t
+    y;
 
-  Sa=QuantumScale*p->alpha; /* ??? - AT */
-  Da=QuantumScale*q->alpha;
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=QuantumRange*Mathematics(QuantumScale*p->red,1.0,
-          QuantumScale*q->red,1.0,args);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=QuantumRange*Mathematics(QuantumScale*p->green,1.0,
-          QuantumScale*q->green,1.0,args);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=QuantumRange*Mathematics(QuantumScale*p->blue,1.0,
-          QuantumScale*q->blue,1.0,args);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Mathematics(QuantumScale*p->black,1.0,
-          QuantumScale*q->black,1.0,args);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-Mathematics(Sa,1.0,Da,1.0,args));
-      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*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->black=gamma*Mathematics(QuantumScale*p->black*Sa,Sa,
-      QuantumScale*q->black*Da,Da,args);
-}
+  size_t
+    channels;
 
-static inline void CompositePlus(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
   /*
-    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 equivalent
-    "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 CompositePixelInfoPlus() function is defined in
-    "composite-private.h" so it can also be used for Image Blending.
+    Prepare composite image.
   */
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=p->red+q->red;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=p->green+q->green;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=p->blue+q->blue;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=p->black+q->black;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=p->alpha+q->alpha-QuantumRange;
-      return;
-    }
-  CompositePixelInfoPlus(p,p->alpha,q,q->alpha,composite);
-}
-
-static inline MagickRealType Minus(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,
-  const MagickRealType magick_unused(Da))
-{
+  modify_outside_overlay=MagickFalse;
+  value=GetImageArtifact(composite_image,"compose:outside-overlay");
+  if (value != (const char *) NULL)
+    modify_outside_overlay=IsMagickTrue(value);
   /*
-    Minus Source from Destination
-
-      f(Sc,Dc) = Sc - Dc
+    Composite image.
   */
-  return(Sca+Dca-2.0*Dca*Sa);
-}
-
-static inline void CompositeMinus(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=p->red-q->red;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=p->green-q->green;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=p->blue-q->blue;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=p->black-q->black;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-(Sa-Da));
-      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*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->black=gamma*Minus(p->black*Sa,Sa,q->black*Da,Da);
-}
+  status=MagickTrue;
+  progress=0;
+  image_view=AcquireCacheView(image);
+  composite_view=AcquireCacheView(composite_image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const Quantum
+      *pixels;
 
-static inline MagickRealType ModulusAdd(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
-{
-  MagickRealType
-    pixel;
+    register const Quantum
+      *restrict p;
 
-  pixel=p+q;
-  if (pixel > QuantumRange)
-    pixel-=(QuantumRange+1.0);
-  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
-}
+    register Quantum
+      *restrict q;
 
-static inline void CompositeModulusAdd(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
+    register ssize_t
+      x;
 
-  if (image->channel_mask != DefaultChannels)
+    if (status == MagickFalse)
+      continue;
+    if (modify_outside_overlay == MagickFalse)
+      {
+        if (y < y_offset)
+          continue;
+        if ((y-y_offset) >= (ssize_t) composite_image->rows)
+          continue;
+      }
+    /*
+      If pixels is NULL, y is outside overlay region.
+    */
+    pixels=(Quantum *) NULL;
+    p=(Quantum *) NULL;
+    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);
+        if (p == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        pixels=p;
+        if (x_offset < 0)
+          p-=x_offset*GetPixelChannels(composite_image);
+      }
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
     {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=ModulusAdd(p->red,1.0,q->red,1.0);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=ModulusAdd(p->green,1.0,q->green,1.0);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=ModulusAdd(p->blue,1.0,q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=ModulusAdd(p->black,1.0,q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=ModulusAdd(p->alpha,1.0,q->alpha,1.0);
-      return;
-    }
-  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=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->black=ModulusAdd(p->black,Sa,q->black,Da);
-}
-
-static inline MagickRealType ModulusSubtract(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
-{
-  MagickRealType
-    pixel;
+      MagickRealType
+        alpha,
+        Da,
+        Dc,
+        gamma,
+        Sa,
+        Sc;
 
-  pixel=p-q;
-  if (pixel < 0.0)
-    pixel+=(QuantumRange+1.0);
-  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
-}
+      register ssize_t
+        i;
 
-static inline void CompositeModulusSubtract(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
+      if (modify_outside_overlay == MagickFalse)
+        {
+          if (x < x_offset)
+            {
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          if ((x-x_offset) >= (ssize_t) composite_image->columns)
+            break;
+        }
+      if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
+          ((x-x_offset) >= (ssize_t) composite_image->columns))
+        {
+          Quantum
+            source[MaxPixelChannels];
 
-  if (image->channel_mask != DefaultChannels)
-    {
+          /*
+            Virtual composite:
+              Sc: source color.
+              Dc: destination color.
+          */
+          (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
+            source,exception);
+          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+          {
+            PixelChannel
+              channel;
+
+            PixelTrait
+              composite_traits,
+              traits;
+
+            channel=GetPixelChannelMapChannel(image,i);
+            traits=GetPixelChannelMapTraits(image,channel);
+            composite_traits=GetPixelChannelMapTraits(composite_image,
+              channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            q[i]=source[channel];
+          }
+          q+=GetPixelChannels(image);
+          continue;
+        }
       /*
-        Handle channels as separate grayscale channels,
+        Authentic composite:
+          Sa:  normalized source alpha.
+          Da:  normalized destination alpha.
       */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=ModulusSubtract(p->red,1.0,q->red,1.0);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=ModulusSubtract(p->green,1.0,q->green,1.0);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=ModulusSubtract(p->blue,1.0,q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=ModulusSubtract(p->black,1.0,q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=ModulusSubtract(p->alpha,1.0,q->alpha,1.0);
-      return;
+      Sa=QuantumScale*GetPixelAlpha(composite_image,p);
+      Da=QuantumScale*GetPixelAlpha(image,q);
+      alpha=Sa*(-Da)+Sa+Da;
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        PixelChannel
+          channel;
+
+        PixelTrait
+          composite_traits,
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (composite_traits == UndefinedPixelTrait))
+          continue;
+        if ((traits & CopyPixelTrait) != 0)
+          {
+            if (channel != AlphaPixelChannel)
+              {
+                /*
+                  Copy channel.
+                */
+                q[i]=GetPixelChannel(composite_image,channel,p);
+                continue;
+              }
+            /*
+              Set alpha channel.
+            */
+            q[i]=ClampToQuantum(QuantumRange*alpha);
+            continue;
+          }
+        /*
+          Sc: source color.
+          Dc: destination color.
+        */
+        Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
+        Dc=(MagickRealType) q[i];
+        gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
+      }
+      p+=GetPixelChannels(composite_image);
+      channels=GetPixelChannels(composite_image);
+      if (p >= (pixels+channels*composite_image->columns))
+        p=pixels;
+      q+=GetPixelChannels(image);
     }
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma = RoundToUnity(Sa+Da-Sa*Da);
-  composite->alpha=(MagickRealType) QuantumRange*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->black=ModulusSubtract(p->black,Sa,q->black,Da);
-}
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
 
-static  inline MagickRealType Multiply(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  return(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_CompositeImage)
+#endif
+        proceed=SetImageProgress(image,CompositeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  composite_view=DestroyCacheView(composite_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
 }
 
-static inline void CompositeMultiply(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
+MagickExport MagickBooleanType CompositeImage(Image *image,
+  const CompositeOperator compose,const Image *composite_image,
+  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
 {
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
+#define CompositeImageTag  "Composite/Image"
 
-  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=QuantumScale*p->red*q->red;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=QuantumScale*p->green*q->green;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=QuantumScale*p->blue*q->blue;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumScale*p->black*q->black;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-Sa*Da);
-      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*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->black=gamma*Multiply(QuantumScale*p->black*Sa,Sa,
-      QuantumScale*q->black*Da,Da);
-}
+  CacheView
+    *composite_view,
+    *image_view;
 
-#if 0
-static inline MagickRealType Out(const MagickRealType p,const MagickRealType Sa,
-  const MagickRealType magick_unused(q),const MagickRealType Da)
-{
-  return(Sa*p*(1.0-Da));
-}
-#endif
+  const char
+    *value;
 
-static inline void CompositeOut(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-#if 0
-  MagickRealType
-    Sa,
-    Da,
-    gamma;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=Sa*(1.0-Da);
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  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->black=gamma*Out(p->black,Sa,q->black,Da);
-#else
-  /* Simplified to a negated multiply of the Alpha Channel */
-  *composite=*p; /* structure copy */
-  composite->alpha=p->alpha*(1.0-QuantumScale*q->alpha);
-#endif
-}
+  double
+    sans;
 
-static MagickRealType PegtopLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    PegTop: A Soft-Light alternative: A continuous version of the Softlight
-    function, producing very similar results.
+  GeometryInfo
+    geometry_info;
 
-    f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
+  Image
+    *destination_image;
 
-    See http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
-  */
-  if (fabs(Da) < MagickEpsilon)
-    return(Sca);
-  return(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-Da)+Dca*(1.0-Sa));
-}
+  MagickBooleanType
+    modify_outside_overlay,
+    status;
+
+  MagickOffsetType
+    progress;
 
-static inline void CompositePegtopLight(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*PegtopLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*PegtopLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*PegtopLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*PegtopLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
+    amount,
+    destination_dissolve,
+    midpoint,
+    percent_brightness,
+    percent_saturation,
+    source_dissolve,
+    threshold;
 
-static MagickRealType PinLight(const MagickRealType Sca,const MagickRealType Sa,
-  const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    PinLight: A Photoshop 7 composition method
-    http://www.simplefilter.de/en/basics/mixmods.html
+  MagickStatusType
+    flags;
 
-    f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
-  */
-  if (Dca*Sa < Da*(2.0*Sca-Sa))
-    return(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
-  if ((Dca*Sa) > (2.0*Sca*Da))
-    return(Sca*Da+Sca+Dca*(1.0-Sa));
-  return(Sca*(1.0-Da)+Dca);
-}
+  ssize_t
+    y;
 
-static inline void CompositePinLight(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*PinLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*PinLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*PinLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*PinLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
+  size_t
+    channels;
 
-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)
+     Composition based on the SVG specification:
+
+     A Composition is defined by...
+        Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
+        Blending areas :  X = 1     for area of overlap, ie: f(Sc,Dc)
+                          Y = 1     for source preserved
+                          Z = 1     for destination preserved
+
+     Conversion to transparency (then optimized)
+        Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
+        Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
+
+     Where...
+        Sca = Sc*Sa     normalized Source color divided by Source alpha
+        Dca = Dc*Da     normalized Dest color divided by Dest alpha
+        Dc' = Dca'/Da'  the desired color value for this channel.
+
+     Da' in in the follow formula as 'gamma'  The resulting alpla value.
+
+     Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
+     the following optimizations...
+        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.
   */
-  return(Sca+Dca-Sca*Dca);
-}
-
-static inline void CompositeScreen(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)
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(composite_image != (Image *) NULL);
+  assert(composite_image->signature == MagickSignature);
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+    return(MagickFalse);
+  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
     {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=QuantumRange*Screen(QuantumScale*p->red,
-          QuantumScale*q->red);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=QuantumRange*Screen(QuantumScale*p->green,
-          QuantumScale*q->green);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=QuantumRange*Screen(QuantumScale*p->blue,
-          QuantumScale*q->blue);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Screen(QuantumScale*p->black,
-          QuantumScale*q->black);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-Screen(Sa,Da));
-      return;
-    }
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*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->black=gamma*Screen(p->black*Sa,q->black*Da);
-}
-
-static MagickRealType SoftLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  MagickRealType
-    alpha,
-    beta;
-
-  /*
-    New specification:  March 2009 SVG specification.
-  */
-  alpha=Dca/Da;
-  if ((2.0*Sca) < Sa)
-    return(Dca*(Sa+(2.0*Sca-Sa)*(1.0-alpha))+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
-    {
-      beta=Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*alpha*(4.0*alpha+1.0)*(alpha-1.0)+7.0*
-        alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
-      return(beta);
-    }
-  beta=Dca*Sa+Da*(2.0*Sca-Sa)*(pow(alpha,0.5)-alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
-  return(beta);
-}
-
-static inline void CompositeSoftLight(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*SoftLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*SoftLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*SoftLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*SoftLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static inline MagickRealType Threshold(const MagickRealType p,
-  const MagickRealType q,const MagickRealType threshold,
-  const MagickRealType amount)
-{
-  MagickRealType
-    delta;
-
-  /*
-    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
-
-    Deprecated.
-  */
-  delta=p-q;
-  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
-    return(q);
-  return(q+delta*amount);
-}
-
-static inline void CompositeThreshold(const PixelInfo *p,const PixelInfo *q,
-  const MagickRealType threshold,const MagickRealType amount,
-  PixelInfo *composite)
-{
-  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->alpha=Threshold(p->alpha,q->alpha,threshold,amount);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=Threshold(p->black,q->black,threshold,amount);
-}
-
-
-static MagickRealType VividLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    VividLight: A Photoshop 7 composition method.  See
-    http://www.simplefilter.de/en/basics/mixmods.html.
-
-    f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
-  */
-  if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
-    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  if ((2.0*Sca) <= Sa)
-    return(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  return(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeVividLight(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*VividLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*VividLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*VividLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*VividLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static MagickRealType Xor(const MagickRealType Sca,const MagickRealType Sa,
-  const MagickRealType Dca,const MagickRealType Da)
-{
-  return(Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeXor(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=Sa+Da-2.0*Sa*Da;        /* Xor blend mode X=0,Y=1,Z=1 */
-  composite->alpha=(MagickRealType) QuantumRange*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);
-  composite->blue=gamma*Xor(p->blue*Sa,Sa,q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Xor(p->black*Sa,Sa,q->black*Da,Da);
-}
-
-static void HSBComposite(const double hue,const double saturation,
-  const double brightness,double *red,double *green,
-  double *blue)
-{
-  double
-    f,
-    h,
-    p,
-    q,
-    t;
-
-  /*
-    Convert HSB to RGB colorspace.
-  */
-  assert(red != (double *) NULL);
-  assert(green != (double *) NULL);
-  assert(blue != (double *) NULL);
-  if (saturation == 0.0)
-    {
-      *red=(double) QuantumRange*brightness;
-      *green=(*red);
-      *blue=(*red);
-      return;
-    }
-  h=6.0*(hue-floor(hue));
-  f=h-floor((double) h);
-  p=brightness*(1.0-saturation);
-  q=brightness*(1.0-saturation*f);
-  t=brightness*(1.0-saturation*(1.0-f));
-  switch ((int) h)
-  {
-    case 0:
-    default:
-    {
-      *red=(double) QuantumRange*brightness;
-      *green=(double) QuantumRange*t;
-      *blue=(double) QuantumRange*p;
-      break;
-    }
-    case 1:
-    {
-      *red=(double) QuantumRange*q;
-      *green=(double) QuantumRange*brightness;
-      *blue=(double) QuantumRange*p;
-      break;
-    }
-    case 2:
-    {
-      *red=(double) QuantumRange*p;
-      *green=(double) QuantumRange*brightness;
-      *blue=(double) QuantumRange*t;
-      break;
-    }
-    case 3:
-    {
-      *red=(double) QuantumRange*p;
-      *green=(double) QuantumRange*q;
-      *blue=(double) QuantumRange*brightness;
-      break;
-    }
-    case 4:
-    {
-      *red=(double) QuantumRange*t;
-      *green=(double) QuantumRange*p;
-      *blue=(double) QuantumRange*brightness;
-      break;
-    }
-    case 5:
-    {
-      *red=(double) QuantumRange*brightness;
-      *green=(double) QuantumRange*p;
-      *blue=(double) QuantumRange*q;
-      break;
+      status=CompositeOverImage(image,composite_image,x_offset,y_offset,
+        exception);
+      return(status);
     }
-  }
-}
-
-MagickExport MagickBooleanType CompositeImage(Image *image,
-  const CompositeOperator compose,const Image *composite_image,
-  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
-{
-#define CompositeImageTag  "Composite/Image"
-
-  CacheView
-    *composite_view,
-    *image_view;
-
-  const char
-    *value;
-
-  double
-    sans;
-
-  GeometryInfo
-    geometry_info;
-
-  Image
-    *destination_image;
-
-  MagickBooleanType
-    modify_outside_overlay,
-    status;
-
-  MagickOffsetType
-    progress;
-
-  MagickRealType
-    amount,
-    destination_dissolve,
-    midpoint,
-    percent_brightness,
-    percent_saturation,
-    source_dissolve,
-    threshold;
-
-  MagickStatusType
-    flags;
-
-  ssize_t
-    y;
-
-  /*
-    Prepare composite image.
-  */
-  assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  assert(composite_image != (Image *) NULL);
-  assert(composite_image->signature == MagickSignature);
-  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
-    return(MagickFalse);
   destination_image=(Image *) NULL;
   amount=0.5;
   destination_dissolve=1.0;
@@ -1656,7 +636,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       image_view=AcquireCacheView(image);
       composite_view=AcquireCacheView(composite_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp parallel for schedule(dynamic,4) shared(status)
+#pragma omp parallel for schedule(static,4) shared(status)
 #endif
       for (y=0; y < (ssize_t) composite_image->rows; y++)
       {
@@ -1715,7 +695,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       image_view=DestroyCacheView(image_view);
       return(status);
     }
-    case CopyOpacityCompositeOp:
+    case CopyAlphaCompositeOp:
     case ChangeMaskCompositeOp:
     {
       /*
@@ -2020,8 +1000,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
             Mask with the 'invalid pixel mask' in alpha channel.
           */
           pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
-            pixel.alpha)*(1.0-QuantumScale*
-            GetPixelAlpha(composite_image,p)));
+            pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
           SetPixelInfoPixel(destination_image,&pixel,q);
           p+=GetPixelChannels(composite_image);
           q+=GetPixelChannels(destination_image);
@@ -2146,7 +1125,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
   image_view=AcquireCacheView(image);
   composite_view=AcquireCacheView(composite_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-//  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2154,8 +1133,11 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       *pixels;
 
     double
+      blue,
       brightness,
+      green,
       hue,
+      red,
       saturation;
 
     register const Quantum
@@ -2167,1060 +1149,1037 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     register ssize_t
       x;
 
-MagickBooleanType composite_channels;
-
     if (status == MagickFalse)
       continue;
     if (modify_outside_overlay == MagickFalse)
-      {
-        if (y < y_offset)
-          continue;
-        if ((y-y_offset) >= (ssize_t) composite_image->rows)
-          continue;
-      }
-    /*
-      If pixels is NULL, y is outside overlay region.
-    */
-    pixels=(Quantum *) NULL;
-    p=(Quantum *) NULL;
-    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);
-        if (p == (const Quantum *) NULL)
-          {
-            status=MagickFalse;
-            continue;
-          }
-        pixels=p;
-        if (x_offset < 0)
-          p-=x_offset*GetPixelChannels(composite_image);
-      }
-    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (Quantum *) NULL)
-      {
-        status=MagickFalse;
-        continue;
-      }
-    hue=0.0;
-    saturation=0.0;
-    brightness=0.0;
-    for (x=0; x < (ssize_t) image->columns; x++)
-    {
-      if (modify_outside_overlay == MagickFalse)
-        {
-          if (x < x_offset)
-            {
-              q+=GetPixelChannels(image);
-              continue;
-            }
-          if ((x-x_offset) >= (ssize_t) composite_image->columns)
-            break;
-        }
-      composite_channels=MagickFalse;
-      switch (compose)
-      {
-        case AtopCompositeOp:
-        case ClearCompositeOp:
-        case ColorDodgeCompositeOp:
-        case CopyCompositeOp:
-        case DarkenCompositeOp:
-        case DarkenIntensityCompositeOp:
-        case DifferenceCompositeOp:
-        case DivideDstCompositeOp:
-        case DivideSrcCompositeOp:
-        case DstAtopCompositeOp:
-        case DstCompositeOp:
-        case DstInCompositeOp:
-        case DstOverCompositeOp:
-        case DstOutCompositeOp:
-        case ExclusionCompositeOp:
-        case InCompositeOp:
-        case LightenCompositeOp:
-        case LightenIntensityCompositeOp:
-        case MathematicsCompositeOp:
-        case MinusDstCompositeOp:
-        case MinusSrcCompositeOp:
-        case ModulusAddCompositeOp:
-        case ModulusSubtractCompositeOp:
-        case MultiplyCompositeOp:
-        case NoCompositeOp:
-        case OutCompositeOp:
-        case OverCompositeOp:
-        case PlusCompositeOp:
-        case ReplaceCompositeOp:
-        case ScreenCompositeOp:
-        case SrcAtopCompositeOp:
-        case SrcCompositeOp:
-        case SrcInCompositeOp:
-        case SrcOutCompositeOp:
-        case SrcOverCompositeOp:
-        case XorCompositeOp:
-        {
-          composite_channels=MagickTrue;
-          break;
-        }
-        default:
-          break;
-      }
-      if (composite_channels != MagickFalse) {
-        MagickRealType
-          alpha,
-          Da,
-          Dc,
-          gamma,
-          Sa,
-          Sc;
-
-        register ssize_t
-          i;
-
-        if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
-            ((x-x_offset) >= (ssize_t) composite_image->columns))
-          {
-            Quantum
-              source[MaxPixelChannels];
-
-            /*
-              Virtual composite:
-                Sc: source color.
-                Dc: destination color.
-            */
-            (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
-              source,exception);
-            for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
-            {
-              MagickRealType
-                pixel;
-
-              PixelChannel
-                channel;
-
-              PixelTrait
-                traits;
-
-              channel=GetPixelChannelMapChannel(image,i);
-              traits=GetPixelChannelMapTraits(image,channel);
-              if (traits == UndefinedPixelTrait)
-                continue;
-              switch (compose)
-              {
-                case ClearCompositeOp:
-                case CopyCompositeOp:
-                case ReplaceCompositeOp:
-                case SrcCompositeOp:
-                {
-                  pixel=0.0;
-                  if (channel == AlphaPixelChannel)
-                    pixel=(MagickRealType) TransparentAlpha;
-                  break;
-                }
-                case DstAtopCompositeOp:
-                case InCompositeOp:
-                case OutCompositeOp:
-                case SrcInCompositeOp:
-                case SrcOutCompositeOp:
-                {
-                  pixel=(MagickRealType) q[i];
-                  if (channel == AlphaPixelChannel)
-                    pixel=(MagickRealType) TransparentAlpha;
-                  break;
-                }
-                default:
-                {
-                  pixel=source[channel];
-                  break;
-                }
-              }
-              q[i]=ClampToQuantum(pixel);
-            }
-            q+=GetPixelChannels(image);
-            continue;
-          }
-        /*
-          Authentic composite:
-            Sa: source normalized alpha.
-            Da: destination normalized alpha.
-        */
-        Sa=QuantumScale*GetPixelAlpha(composite_image,p);
-        Da=QuantumScale*GetPixelAlpha(image,q);
-        switch (compose)
-        {
-          case DarkenCompositeOp:
-          case DstAtopCompositeOp:
-          case DstInCompositeOp:
-          case InCompositeOp:
-          case LightenCompositeOp:
-          case SrcInCompositeOp:
-          {
-            alpha=Sa*Da;
-            break;
-          }
-          case ColorDodgeCompositeOp:
-          case DifferenceCompositeOp:
-          case DivideDstCompositeOp:
-          case DivideSrcCompositeOp:
-          case ExclusionCompositeOp:
-          case MathematicsCompositeOp:
-          case MinusDstCompositeOp:
-          case MinusSrcCompositeOp:
-          case ModulusAddCompositeOp:
-          case ModulusSubtractCompositeOp:
-          case MultiplyCompositeOp:
-          case ScreenCompositeOp:
-          {
-            alpha=RoundToUnity(Sa+Da-Sa*Da);
-            break;
-          }
-          case DstOverCompositeOp:
-          {
-            alpha=Da*(-Sa)+Da+Sa;
-            break;
-          }
-          case DstOutCompositeOp:
-          {
-            alpha=Da*(1.0-Sa);
-            break;
-          }
-          case OutCompositeOp:
-          case SrcOutCompositeOp:
-          {
-            alpha=Sa*(1.0-Da);
-            break;
-          }
-          case OverCompositeOp:
-          case SrcOverCompositeOp:
-          {
-            alpha=Sa*(-Da)+Sa+Da;
-            break;
-          }
-          case PlusCompositeOp:
-          {
-            alpha=RoundToUnity(Sa+Da);
-            break;
-          }
-          case XorCompositeOp:
-          {
-            alpha=Sa+Da-2.0*Sa*Da;
-            break;
-          }
-          default:
-          {
-            alpha=1.0;
-            break;
-          }
-        }
-        for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
-        {
-          MagickRealType
-            pixel;
-
-          PixelChannel
-            channel;
-
-          PixelTrait
-            composite_traits,
-            traits;
-
-          channel=GetPixelChannelMapChannel(image,i);
-          traits=GetPixelChannelMapTraits(image,channel);
-          composite_traits=GetPixelChannelMapTraits(composite_image,channel);
-          if ((traits == UndefinedPixelTrait) ||
-              (composite_traits == UndefinedPixelTrait))
-            continue;
-          /*
-            Sc: source color.
-            Dc: destination color.
-          */
-          Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
-          Dc=(MagickRealType) q[i];
-          if ((traits & CopyPixelTrait) != 0)
-            {
-              if (channel != AlphaPixelChannel)
-                {
-                  /*
-                    Copy channel.
-                  */
-                  q[i]=Sc;
-                  continue;
-                }
-              /*
-                Set alpha channel.
-              */
-              pixel=0.0;
-              switch (compose)
-              {
-                case AtopCompositeOp:
-                case SrcAtopCompositeOp:
-                case DstCompositeOp:
-                case NoCompositeOp:
-                {
-                  pixel=QuantumRange*Da;
-                  break;
-                }
-                case CopyCompositeOp:
-                case DstAtopCompositeOp:
-                case ReplaceCompositeOp:
-                case SrcCompositeOp:
-                {
-                  pixel=QuantumRange*Sa;
-                  break;
-                }
-                case DarkenIntensityCompositeOp:
-                {
-                  pixel=Sa*GetPixelIntensity(composite_image,p) <
-                    Da*GetPixelIntensity(image,q) ? Sa : Da;
-                  break;
-                }
-                case LightenIntensityCompositeOp:
-                {
-                  pixel=Sa*GetPixelIntensity(composite_image,p) >
-                    Da*GetPixelIntensity(image,q) ? Sa : Da;
-                  break;
-                }
-                default:
-                {
-                  pixel=QuantumRange*alpha;
-                  break;
-                }
-              }
-              q[i]=ClampToQuantum(pixel);
-              continue;
-            }
-          /*
-            Porter-Duff compositions.
-          */
-          switch (compose)
-          {
-            case DarkenCompositeOp:
-            case LightenCompositeOp:
-            {
-              gamma=1.0-QuantumScale*Dc;
-              break;
-            }
-            default:
-              break;
-          }
-          gamma=QuantumRange/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
-          pixel=0.0;
-          switch (compose)
-          {
-            case AtopCompositeOp:
-            case SrcAtopCompositeOp:
-            {
-              pixel=Sc*Sa+Dc*(1.0-Sa);
-              break;
-            }
-            case ColorDodgeCompositeOp:
-            {
-              if ((fabs((Sa*Sc)-Sa) < MagickEpsilon) &&
-                  (fabs((Da*Dc)) < MagickEpsilon))
-                {
-                  pixel=gamma*((Sa*Sc)*(1.0-Da)+(Da*Dc)*(1.0-Sa));
-                  break;
-                }
-              if (fabs((Sa*Sc)-Sa) < MagickEpsilon)
-                {
-                  pixel=gamma*(Sa*Da+(Sa*Sc)*(1.0-Da)+(Da*Dc)*(1.0-Sa));
-                  break;
-                }
-              pixel=gamma*((Da*Dc)*Sa*Sa/(Sa-(Sa*Sc))+(Sa*Sc)*(1.0-Da)+(Da*Dc)*
-                (1.0-Sa));
-              break;
-            }
-            case CopyCompositeOp:
-            case ReplaceCompositeOp:
-            case SrcCompositeOp:
-            {
-              pixel=Sc;
-              break;
-            }
-            case DarkenCompositeOp:
-            {
-              if (Sc < Dc)
-                {
-                  pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
-                  break;
-                }
-              pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
-              break;
-            }
-            case DarkenIntensityCompositeOp:
-            {
-              pixel=Sa*GetPixelIntensity(composite_image,p) <
-                Da*GetPixelIntensity(image,q) ? Sc : Dc;
-              break;
-            }
-            case DifferenceCompositeOp:
-            {
-              pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
-              break;
-            }
-            case DivideDstCompositeOp:
-            {
-              if ((fabs((QuantumScale*Sa*Sc)) < MagickEpsilon) &&
-                  (fabs((QuantumScale*Da*Dc)) < MagickEpsilon))
-                {
-                  pixel=gamma*((QuantumScale*Sa*Sc)*(1.0-Da)+
-                    (QuantumScale*Da*Dc)*(1.0-Sa));
-                  break;
-                }
-              if (fabs((QuantumScale*Da*Dc)) < MagickEpsilon)
-                {
-                  pixel=gamma*(Sa*Da+(QuantumScale*Sa*Sc)*(1.0-Da)+
-                    (QuantumScale*Da*Dc)*(1.0-Sa));
-                  break;
-                }
-              pixel=gamma*((QuantumScale*Sa*Sc)*Da*Da/(QuantumScale*Da*Dc)+
-                (QuantumScale*Sa*Sc)*(1.0-Da)+(QuantumScale*Da*Dc)*(1.0-Sa));
-              break;
-            }
-            case DivideSrcCompositeOp:
-            {
-              if ((fabs((QuantumScale*Da*Dc)) < MagickEpsilon) &&
-                  (fabs((QuantumScale*Sa*Sc)) < MagickEpsilon))
-                {
-                  pixel=gamma*((QuantumScale*Da*Dc)*(1.0-Sa)+
-                    (QuantumScale*Sa*Sc)*(1.0-Da));
-                  break;
-                }
-              if (fabs((QuantumScale*Sa*Sc)) < MagickEpsilon)
-                {
-                  pixel=gamma*(Da*Sa+(QuantumScale*Da*Dc)*(1.0-Sa)+
-                    (QuantumScale*Sa*Sc)*(1.0-Da));
-                  break;
-                }
-              pixel=gamma*((QuantumScale*Da*Dc)*Sa*Sa/(QuantumScale*Sa*Sc)+
-                (QuantumScale*Da*Dc)*(1.0-Sa)+(QuantumScale*Sa*Sc)*(1.0-Da));
-              break;
-            }
-            case DstAtopCompositeOp:
-            {
-              pixel=Dc*Da+Sc*(1.0-Da);
-              break;
-            }
-            case DstCompositeOp:
-            case NoCompositeOp:
-            {
-              pixel=Dc;
-              break;
-            }
-            case DstInCompositeOp:
-            {
-              pixel=gamma*(Sa*Dc*Sa);
-              break;
-            }
-            case DstOutCompositeOp:
-            {
-              pixel=gamma*(Da*Dc*(1.0-Sa));
-              break;
-            }
-            case DstOverCompositeOp:
-            {
-              pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
-              break;
-            }
-            case ExclusionCompositeOp:
-            {
-              pixel=gamma*((QuantumScale*Sa*Sc)*Da+(QuantumScale*Da*Dc)*Sa-2.0*
-                (QuantumScale*Sa*Sc)*(QuantumScale*Da*Dc)+(QuantumScale*Sa*Sc)*
-                (1.0-Da)+(QuantumScale*Da*Dc)*(1.0-Sa));
-              break;
-            }
-            case InCompositeOp:
-            case SrcInCompositeOp:
-            {
-              pixel=gamma*(Da*Sc*Da);
-              break;
-            }
-            case LightenIntensityCompositeOp:
-            {
-              pixel=Sa*GetPixelIntensity(composite_image,p) >
-                Da*GetPixelIntensity(image,q) ? Sc : Dc;
-              break;
-            }
-            case MathematicsCompositeOp:
-            {
-              pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
-                Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
-                Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
-              break;
-            }
-            case MinusDstCompositeOp:
-            {
-              pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
-              break;
-            }
-            case MinusSrcCompositeOp:
-            {
-              pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
-              break;
-            }
-            case LightenCompositeOp:
-            {
-              if (Sc > Dc)
-                {
-                  pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
-                  break;
-                }
-              pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
-              break;
-            }
-            case ModulusAddCompositeOp:
-            {
-              pixel=Sc+Dc;
-              if (pixel > QuantumRange)
-                pixel-=(QuantumRange+1.0);
-              pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
-              break;
-            }
-            case ModulusSubtractCompositeOp:
-            {
-              pixel=Sc+Dc;
-              if (pixel < 0.0)
-                pixel+=(QuantumRange+1.0);
-              pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
-              break;
-            }
-            case MultiplyCompositeOp:
-            {
-              pixel=gamma*((QuantumScale*Sa*Sc)*(QuantumScale*Da*Dc)+
-                (QuantumScale*Sa*Sc)*(1.0-Da)+(QuantumScale*Da*Dc)*(1.0-Sa));
-              break;
-            }
-            case OutCompositeOp:
-            case SrcOutCompositeOp:
-            {
-              pixel=gamma*(Sa*Sc*(1.0-Da));
-              break;
-            }
-            case OverCompositeOp:
-            case SrcOverCompositeOp:
-            {
-              pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
-              break;
-            }
-            case PlusCompositeOp:
-            {
-              pixel=gamma*(Sa*Sc+Da*Dc);
-              break;
-            }
-            case ScreenCompositeOp:
+      {
+        if (y < y_offset)
+          continue;
+        if ((y-y_offset) >= (ssize_t) composite_image->rows)
+          continue;
+      }
+    /*
+      If pixels is NULL, y is outside overlay region.
+    */
+    pixels=(Quantum *) NULL;
+    p=(Quantum *) NULL;
+    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);
+        if (p == (const Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        pixels=p;
+        if (x_offset < 0)
+          p-=x_offset*GetPixelChannels(composite_image);
+      }
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    hue=0.0;
+    saturation=0.0;
+    brightness=0.0;
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      MagickRealType
+        alpha,
+        Da,
+        Dc,
+        Dca,
+        gamma,
+        Sa,
+        Sc,
+        Sca;
+
+      register ssize_t
+        i;
+
+      if (modify_outside_overlay == MagickFalse)
+        {
+          if (x < x_offset)
             {
-              pixel=gamma*((Sa*Sc)+(Da*Dc)-(Sa*Sc)*(Da*Dc));
-              break;
+              q+=GetPixelChannels(image);
+              continue;
             }
-            case XorCompositeOp:
+          if ((x-x_offset) >= (ssize_t) composite_image->columns)
+            break;
+        }
+      if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
+          ((x-x_offset) >= (ssize_t) composite_image->columns))
+        {
+          Quantum
+            source[MaxPixelChannels];
+
+          /*
+            Virtual composite:
+              Sc: source color.
+              Dc: destination color.
+          */
+          (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
+            source,exception);
+          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+          {
+            MagickRealType
+              pixel;
+
+            PixelChannel
+              channel;
+
+            PixelTrait
+              composite_traits,
+              traits;
+
+            channel=GetPixelChannelMapChannel(image,i);
+            traits=GetPixelChannelMapTraits(image,channel);
+            composite_traits=GetPixelChannelMapTraits(composite_image,
+              channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            switch (compose)
             {
-              pixel=gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
-              break;
+              case ChangeMaskCompositeOp:
+              case CopyAlphaCompositeOp:
+              case DstAtopCompositeOp:
+              case DstInCompositeOp:
+              case InCompositeOp:
+              case OutCompositeOp:
+              case SrcInCompositeOp:
+              case SrcOutCompositeOp:
+              {
+                pixel=(MagickRealType) q[i];
+                if (channel == AlphaPixelChannel)
+                  pixel=(MagickRealType) TransparentAlpha;
+                break;
+              }
+              case ClearCompositeOp:
+              case CopyCompositeOp:
+              case ReplaceCompositeOp:
+              case SrcCompositeOp:
+              {
+                if (channel == AlphaPixelChannel)
+                  {
+                    pixel=(MagickRealType) TransparentAlpha;
+                    break;
+                  }
+                pixel=0.0;
+                break;
+              }
+              case BlendCompositeOp:
+              case DissolveCompositeOp:
+              {
+                if (channel == AlphaPixelChannel)
+                  {
+                    pixel=destination_dissolve*GetPixelAlpha(composite_image,
+                      source);
+                    break;
+                  }
+                pixel=(MagickRealType) source[channel];
+                break;
+              }
+              default:
+              {
+                pixel=(MagickRealType) source[channel];
+                break;
+              }
             }
-            default:
-              break;
+            q[i]=ClampToQuantum(pixel);
           }
-          q[i]=ClampToQuantum(pixel);
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      /*
+        Authentic composite:
+          Sa:  normalized source alpha.
+          Da:  normalized destination alpha.
+      */
+      Sa=QuantumScale*GetPixelAlpha(composite_image,p);
+      Da=QuantumScale*GetPixelAlpha(image,q);
+      switch (compose)
+      {
+        case BumpmapCompositeOp:
+        {
+          alpha=GetPixelIntensity(composite_image,p)*Sa;
+          break;
+        }
+        case ColorBurnCompositeOp:
+        case ColorDodgeCompositeOp:
+        case DifferenceCompositeOp:
+        case DivideDstCompositeOp:
+        case DivideSrcCompositeOp:
+        case ExclusionCompositeOp:
+        case HardLightCompositeOp:
+        case LinearBurnCompositeOp:
+        case LinearDodgeCompositeOp:
+        case LinearLightCompositeOp:
+        case MathematicsCompositeOp:
+        case MinusDstCompositeOp:
+        case MinusSrcCompositeOp:
+        case ModulusAddCompositeOp:
+        case ModulusSubtractCompositeOp:
+        case MultiplyCompositeOp:
+        case OverlayCompositeOp:
+        case PegtopLightCompositeOp:
+        case PinLightCompositeOp:
+        case ScreenCompositeOp:
+        case SoftLightCompositeOp:
+        case VividLightCompositeOp:
+        {
+          alpha=RoundToUnity(Sa+Da-Sa*Da);
+          break;
+        }
+        case DarkenCompositeOp:
+        case DstAtopCompositeOp:
+        case DstInCompositeOp:
+        case InCompositeOp:
+        case LightenCompositeOp:
+        case SrcInCompositeOp:
+        {
+          alpha=Sa*Da;
+          break;
+        }
+        case DissolveCompositeOp:
+        {
+          alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
+            Sa+destination_dissolve*Da;
+          break;
+        }
+        case DstOverCompositeOp:
+        {
+          alpha=Da*(-Sa)+Da+Sa;
+          break;
+        }
+        case DstOutCompositeOp:
+        {
+          alpha=Da*(1.0-Sa);
+          break;
+        }
+        case OutCompositeOp:
+        case SrcOutCompositeOp:
+        {
+          alpha=Sa*(1.0-Da);
+          break;
+        }
+        case OverCompositeOp:
+        case SrcOverCompositeOp:
+        {
+          alpha=Sa*(-Da)+Sa+Da;
+          break;
+        }
+        case BlendCompositeOp:
+        case PlusCompositeOp:
+        {
+          alpha=RoundToUnity(Sa+Da);
+          break;
+        }
+        case XorCompositeOp:
+        {
+          alpha=Sa+Da-2.0*Sa*Da;
+          break;
         }
-      } else {
-        PixelInfo
-          composite,
-          destination,
-          source,
-          zero;
-
-        GetPixelInfo(image,&zero);
-        source=zero;
-        destination=zero;
-        destination.red=(MagickRealType) GetPixelRed(image,q);
-        destination.green=(MagickRealType) GetPixelGreen(image,q);
-        destination.blue=(MagickRealType) GetPixelBlue(image,q);
-        if (image->colorspace == CMYKColorspace)
-          destination.black=(MagickRealType) GetPixelBlack(image,q);
-        if (image->colorspace == CMYKColorspace)
-          {
-            destination.red=(MagickRealType) QuantumRange-destination.red;
-            destination.green=(MagickRealType) QuantumRange-destination.green;
-            destination.blue=(MagickRealType) QuantumRange-destination.blue;
-            destination.black=(MagickRealType) QuantumRange-destination.black;
-          }
-        if (image->matte != MagickFalse)
-          destination.alpha=(MagickRealType) GetPixelAlpha(image,q);
+        default:
+        {
+          alpha=1.0;
+          break;
+        }
+      }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        MagickRealType
+          pixel;
+
+        PixelChannel
+          channel;
+
+        PixelTrait
+          composite_traits,
+          traits;
+
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (composite_traits == UndefinedPixelTrait))
+          continue;
         /*
-          Handle destination modifications outside overlaid region.
+          Sc: source color.
+          Dc: destination color.
         */
-        composite=destination;
-        if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
-            ((x-x_offset) >= (ssize_t) composite_image->columns))
+        Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
+        Dc=(MagickRealType) q[i];
+        if ((traits & CopyPixelTrait) != 0)
           {
+            if (channel != AlphaPixelChannel)
+              {
+                /*
+                  Copy channel.
+                */
+                q[i]=ClampToQuantum(Sc);
+                continue;
+              }
+            /*
+              Set alpha channel.
+            */
             switch (compose)
             {
-              case DissolveCompositeOp:
-              case BlendCompositeOp:
+              case AtopCompositeOp:
+              case CopyBlackCompositeOp:
+              case CopyBlueCompositeOp:
+              case CopyCyanCompositeOp:
+              case CopyGreenCompositeOp:
+              case CopyMagentaCompositeOp:
+              case CopyRedCompositeOp:
+              case CopyYellowCompositeOp:
+              case SrcAtopCompositeOp:
+              case DstCompositeOp:
+              case NoCompositeOp:
+              {
+                pixel=QuantumRange*Da;
+                break;
+              }
+              case ChangeMaskCompositeOp:
               {
-                composite.alpha=destination_dissolve*(composite.alpha);
+                MagickBooleanType
+                  equivalent;
+
+                if (Da > ((MagickRealType) QuantumRange/2.0))
+                  {
+                    pixel=(MagickRealType) TransparentAlpha;
+                    break;
+                  }
+                equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
+                if (equivalent != MagickFalse)
+                  {
+                    pixel=(MagickRealType) TransparentAlpha;
+                    break;
+                  }
+                pixel=(MagickRealType) OpaqueAlpha;
                 break;
               }
               case ClearCompositeOp:
-              case SrcCompositeOp:
               {
-                CompositeClear(&destination,&composite);
+                pixel=(MagickRealType) TransparentAlpha;
                 break;
               }
-              case InCompositeOp:
-              case SrcInCompositeOp:
-              case OutCompositeOp:
-              case SrcOutCompositeOp:
-              case DstInCompositeOp:
+              case ColorizeCompositeOp:
+              case HueCompositeOp:
+              case LuminizeCompositeOp:
+              case SaturateCompositeOp:
+              {
+                if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+                  {
+                    pixel=QuantumRange*Da;
+                    break;
+                  }
+                if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+                  {
+                    pixel=QuantumRange*Sa;
+                    break;
+                  }
+                if (Sa < Da)
+                  {
+                    pixel=QuantumRange*Da;
+                    break;
+                  }
+                pixel=QuantumRange*Sa;
+                break;
+              }
+              case CopyCompositeOp:
+              case CopyAlphaCompositeOp:
+              case DisplaceCompositeOp:
+              case DistortCompositeOp:
               case DstAtopCompositeOp:
-              case CopyOpacityCompositeOp:
-              case ChangeMaskCompositeOp:
+              case ReplaceCompositeOp:
+              case SrcCompositeOp:
               {
-                composite.alpha=(MagickRealType) TransparentAlpha;
+                pixel=QuantumRange*Sa;
                 break;
               }
-              default:
+              case DarkenIntensityCompositeOp:
               {
-                (void) GetOneVirtualPixelInfo(composite_image,
-                  GetPixelCacheVirtualMethod(composite_image),x-x_offset,y-
-                  y_offset,&composite,exception);
+                pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
+                  (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
                 break;
               }
-            }
-            if (image->colorspace == CMYKColorspace)
+              case LightenIntensityCompositeOp:
+              {
+                pixel=Sa*GetPixelIntensity(composite_image,p) >
+                  Da*GetPixelIntensity(image,q) ? Sa : Da;
+                break;
+              }
+              case ModulateCompositeOp:
+              {
+                if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+                  {
+                    pixel=QuantumRange*Da;
+                    break;
+                  }
+                pixel=QuantumRange*Da;
+                break;
+              }
+              default:
               {
-                composite.red=(MagickRealType) QuantumRange-composite.red;
-                composite.green=(MagickRealType) QuantumRange-composite.green;
-                composite.blue=(MagickRealType) QuantumRange-composite.blue;
-                composite.black=(MagickRealType) QuantumRange-composite.black;
+                pixel=QuantumRange*alpha;
+                break;
               }
-            SetPixelRed(image,ClampToQuantum(composite.red),q);
-            SetPixelGreen(image,ClampToQuantum(composite.green),q);
-            SetPixelBlue(image,ClampToQuantum(composite.blue),q);
-            if (image->matte != MagickFalse)
-              SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
-            if (image->colorspace == CMYKColorspace)
-              SetPixelBlack(image,ClampToQuantum(composite.black),q);
-            q+=GetPixelChannels(image);
+            }
+            q[i]=ClampToQuantum(pixel);
             continue;
           }
         /*
-          Handle normal overlay of source onto destination.
-        */
-        source.red=(MagickRealType) GetPixelRed(composite_image,p);
-        source.green=(MagickRealType) GetPixelGreen(composite_image,p);
-        source.blue=(MagickRealType) GetPixelBlue(composite_image,p);
-        if (composite_image->colorspace == CMYKColorspace)
-          source.black=(MagickRealType) GetPixelBlack(composite_image,p);
-        if (composite_image->colorspace == CMYKColorspace)
-          {
-            source.red=(MagickRealType) QuantumRange-source.red;
-            source.green=(MagickRealType) QuantumRange-source.green;
-            source.blue=(MagickRealType) QuantumRange-source.blue;
-            source.black=(MagickRealType) QuantumRange-source.black;
-          }
-        if (composite_image->matte != MagickFalse)
-          source.alpha=(MagickRealType) GetPixelAlpha(composite_image,p);
-        /*
-          Porter-Duff compositions.
+          Porter-Duff compositions:
+            Sca: source normalized color multiplied by alpha.
+            Dca: normalized destination color multiplied by alpha.
         */
+        Sca=QuantumScale*Sa*Sc;
+        Dca=QuantumScale*Da*Dc;
         switch (compose)
         {
-          case ClearCompositeOp:
+          case DarkenCompositeOp:
+          case LightenCompositeOp:
+          case ModulusSubtractCompositeOp:
           {
-            CompositeClear(&destination,&composite);
+            gamma=1.0-alpha;
             break;
           }
-          case SrcCompositeOp:
-          case CopyCompositeOp:
-          case ReplaceCompositeOp:
+          default:
+            break;
+        }
+        gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        switch (compose)
+        {
+          case AtopCompositeOp:
+          case SrcAtopCompositeOp:
           {
-            composite=source;
+            pixel=Sc*Sa+Dc*(1.0-Sa);
             break;
           }
-          case NoCompositeOp:
-          case DstCompositeOp:
+          case BlendCompositeOp:
+          {
+            pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
             break;
-          case OverCompositeOp:
-          case SrcOverCompositeOp:
+          }
+          case BlurCompositeOp:
+          case DisplaceCompositeOp:
+          case DistortCompositeOp:
+          case CopyCompositeOp:
+          case ReplaceCompositeOp:
+          case SrcCompositeOp:
           {
-            CompositePixelInfoOver(&source,source.alpha,&destination,
-              destination.alpha,&composite);
+            pixel=Sc;
             break;
           }
-          case DstOverCompositeOp:
+          case BumpmapCompositeOp:
           {
-            CompositePixelInfoOver(&destination,destination.alpha,&source,
-              source.alpha,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
             break;
           }
-          case SrcInCompositeOp:
-          case InCompositeOp:
+          case ChangeMaskCompositeOp:
           {
-            CompositeIn(&source,&destination,&composite);
+            pixel=Dc;
             break;
           }
-          case DstInCompositeOp:
+          case ClearCompositeOp:
           {
-            CompositeIn(&destination,&source,&composite);
+            pixel=0.0;
             break;
           }
-          case OutCompositeOp:
-          case SrcOutCompositeOp:
+          case ColorBurnCompositeOp:
           {
-            CompositeOut(&source,&destination,&composite);
+            /*
+              Refer to the March 2009 SVG specification.
+            */
+            if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
+                break;
+              }
+            if (Sca < MagickEpsilon)
+              {
+                pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
+              Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case DstOutCompositeOp:
+          case ColorDodgeCompositeOp:
           {
-            CompositeOut(&destination,&source,&composite);
+            if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if (fabs(Sca-Sa) < MagickEpsilon)
+              {
+                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
+              (1.0-Sa));
             break;
           }
-          case AtopCompositeOp:
-          case SrcAtopCompositeOp:
+          case ColorizeCompositeOp:
           {
-            CompositeAtop(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
+              GetPixelBlue(image,q),&sans,&sans,&brightness);
+            CompositeHSB(GetPixelRed(composite_image,p),
+              GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
+              &hue,&saturation,&sans);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case DstAtopCompositeOp:
+          case CopyAlphaCompositeOp:
           {
-            CompositeAtop(&destination,&source,&composite);
+            if (channel == AlphaPixelChannel)
+              {
+                if (composite_image->matte != MagickFalse)
+                  pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
+                else
+                  pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
+                break;
+              }
+            pixel=Dc;
             break;
           }
-          case XorCompositeOp:
+          case CopyBlackCompositeOp:
           {
-            CompositeXor(&source,&destination,&composite);
+            pixel=(MagickRealType) GetPixelBlack(composite_image,p);
             break;
           }
-          case PlusCompositeOp:
+          case CopyBlueCompositeOp:
+          case CopyYellowCompositeOp:
           {
-            CompositePlus(image,&source,&destination,&composite);
+            pixel=(MagickRealType) GetPixelBlue(composite_image,p);
             break;
           }
-          case MinusDstCompositeOp:
+          case CopyGreenCompositeOp:
+          case CopyMagentaCompositeOp:
           {
-            CompositeMinus(image,&source,&destination,&composite);
+            pixel=(MagickRealType) GetPixelGreen(composite_image,p);
             break;
           }
-          case MinusSrcCompositeOp:
+          case CopyRedCompositeOp:
+          case CopyCyanCompositeOp:
           {
-            CompositeMinus(image,&destination,&source,&composite);
+            pixel=(MagickRealType) GetPixelRed(composite_image,p);
             break;
           }
-          case ModulusAddCompositeOp:
+          case DarkenCompositeOp:
           {
-            CompositeModulusAdd(image,&source,&destination,&composite);
+            /*
+              Darken is equivalent to a 'Minimum' method
+                OR a greyscale version of a binary 'Or'
+                OR the 'Intersection' of pixel sets.
+            */
+            if (Sc < Dc)
+              {
+                pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+                break;
+              }
+            pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
             break;
           }
-          case ModulusSubtractCompositeOp:
+          case DarkenIntensityCompositeOp:
           {
-            CompositeModulusSubtract(image,&source,&destination,&composite);
+            pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
+              (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
             break;
           }
           case DifferenceCompositeOp:
           {
-            CompositeDifference(image,&source,&destination,&composite);
+            pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
             break;
           }
-          case ExclusionCompositeOp:
+          case DissolveCompositeOp:
           {
-            CompositeExclusion(image,&source,&destination,&composite);
+            pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
+              destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
             break;
           }
-          case MultiplyCompositeOp:
+          case DivideDstCompositeOp:
           {
-            CompositeMultiply(image,&source,&destination,&composite);
+            if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if (fabs(Dca) < MagickEpsilon)
+              {
+                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case ScreenCompositeOp:
+          case DivideSrcCompositeOp:
           {
-            CompositeScreen(image,&source,&destination,&composite);
+            if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
+                break;
+              }
+            if (fabs(Sca) < MagickEpsilon)
+              {
+                pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
             break;
           }
-          case DivideDstCompositeOp:
+          case DstAtopCompositeOp:
           {
-            CompositeDivide(image,&source,&destination,&composite);
+            pixel=Dc*Da+Sc*(1.0-Da);
             break;
           }
-          case DivideSrcCompositeOp:
+          case DstCompositeOp:
+          case NoCompositeOp:
           {
-            CompositeDivide(image,&destination,&source,&composite);
+            pixel=Dc;
             break;
           }
-          case DarkenCompositeOp:
+          case DstInCompositeOp:
           {
-            CompositeDarken(image,&source,&destination,&composite);
+            pixel=gamma*(Sa*Dc*Sa);
             break;
           }
-          case LightenCompositeOp:
+          case DstOutCompositeOp:
           {
-            CompositeLighten(image,&source,&destination,&composite);
+            pixel=gamma*(Da*Dc*(1.0-Sa));
             break;
           }
-          case DarkenIntensityCompositeOp:
+          case DstOverCompositeOp:
           {
-            CompositeDarkenIntensity(image,&source,&destination,&composite);
+            pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
             break;
           }
-          case LightenIntensityCompositeOp:
+          case ExclusionCompositeOp:
           {
-            CompositeLightenIntensity(image,&source,&destination,&composite);
+            pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
             break;
           }
-          case MathematicsCompositeOp:
+          case HardLightCompositeOp:
           {
-            CompositeMathematics(image,&source,&destination,&geometry_info,
-              &composite);
+            if ((2.0*Sca) < Sa)
+              {
+                pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
+                  (1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
             break;
           }
-          case ColorDodgeCompositeOp:
+          case HueCompositeOp:
           {
-            CompositeColorDodge(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
+              GetPixelBlue(image,q),&hue,&saturation,&brightness);
+            CompositeHSB(GetPixelRed(composite_image,p),
+              GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
+              &hue,&sans,&sans);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case ColorBurnCompositeOp:
+          case InCompositeOp:
+          case SrcInCompositeOp:
           {
-            CompositeColorBurn(&source,&destination,&composite);
+            pixel=gamma*(Da*Sc*Da);
             break;
           }
-          case LinearDodgeCompositeOp:
+          case LinearBurnCompositeOp:
           {
-            CompositeLinearDodge(&source,&destination,&composite);
+            /*
+              LinearBurn: as defined by Abode Photoshop, according to
+              http://www.simplefilter.de/en/basics/mixmods.html is:
+
+                f(Sc,Dc) = Sc + Dc - 1
+            */
+            pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
             break;
           }
-          case LinearBurnCompositeOp:
+          case LinearDodgeCompositeOp:
           {
-            CompositeLinearBurn(&source,&destination,&composite);
+            pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
             break;
           }
-          case HardLightCompositeOp:
+          case LinearLightCompositeOp:
           {
-            CompositeHardLight(&source,&destination,&composite);
+            /*
+              LinearLight: as defined by Abode Photoshop, according to
+              http://www.simplefilter.de/en/basics/mixmods.html is:
+
+                f(Sc,Dc) = Dc + 2*Sc - 1
+            */
+            pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
             break;
           }
-          case OverlayCompositeOp:
+          case LightenCompositeOp:
           {
-            CompositeHardLight(&destination,&source,&composite);
+            if (Sc > Dc)
+              {
+                pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+                break;
+              }
+            pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
             break;
           }
-          case SoftLightCompositeOp:
+          case LightenIntensityCompositeOp:
           {
-            CompositeSoftLight(&source,&destination,&composite);
+            /*
+              Lighten is equivalent to a 'Maximum' method
+                OR a greyscale version of a binary 'And'
+                OR the 'Union' of pixel sets.
+            */
+            pixel=Sa*GetPixelIntensity(composite_image,p) >
+              Da*GetPixelIntensity(image,q) ? Sc : Dc;
             break;
           }
-          case LinearLightCompositeOp:
+          case LuminizeCompositeOp:
           {
-            CompositeLinearLight(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
+              GetPixelBlue(image,q),&hue,&saturation,&brightness);
+            CompositeHSB(GetPixelRed(composite_image,p),
+              GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
+              &sans,&sans,&brightness);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case PegtopLightCompositeOp:
+          case MathematicsCompositeOp:
           {
-            CompositePegtopLight(&source,&destination,&composite);
+            /*
+              'Mathematics' a free form user control mathematical composition
+              is defined as...
+
+                f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
+
+              Where the arguments A,B,C,D are (currently) passed to composite
+              as a command separated 'geometry' string in "compose:args" image
+              artifact.
+
+                 A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
+
+              Applying the SVG transparency formula (see above), we get...
+
+               Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
+
+               Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
+                 Dca*(1.0-Sa)
+            */
+            pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
+              Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
+              Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
             break;
           }
-          case VividLightCompositeOp:
+          case MinusDstCompositeOp:
           {
-            CompositeVividLight(&source,&destination,&composite);
+            pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
             break;
           }
-          case PinLightCompositeOp:
+          case MinusSrcCompositeOp:
           {
-            CompositePinLight(&source,&destination,&composite);
+            /*
+              Minus source from destination.
+
+                f(Sc,Dc) = Sc - Dc
+            */
+            pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
             break;
           }
-          case ChangeMaskCompositeOp:
+          case ModulateCompositeOp:
           {
-            if ((composite.alpha > ((MagickRealType) QuantumRange/2.0)) ||
-                (IsFuzzyEquivalencePixelInfo(&source,&destination) != MagickFalse))
-              composite.alpha=(MagickRealType) TransparentAlpha;
-            else
-              composite.alpha=(MagickRealType) OpaqueAlpha;
+            ssize_t
+              offset;
+
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
+            if (offset == 0)
+              {
+                pixel=Dc;
+                break;
+              }
+            CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
+              GetPixelBlue(image,q),&hue,&saturation,&brightness);
+            brightness+=(0.01*percent_brightness*offset)/midpoint;
+            saturation*=0.01*percent_saturation;
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case BumpmapCompositeOp:
+          case ModulusAddCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            CompositeBumpmap(&source,&destination,&composite);
+            pixel=Sc+Dc;
+            if (pixel > QuantumRange)
+              pixel-=(QuantumRange+1.0);
+            pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
             break;
           }
-          case DissolveCompositeOp:
+          case ModulusSubtractCompositeOp:
           {
-            CompositePixelInfoOver(&source,source_dissolve*source.alpha,
-              &destination,(MagickRealType) (destination_dissolve*
-              destination.alpha),&composite);
+            pixel=Sc-Dc;
+            if (pixel < 0.0)
+              pixel+=(QuantumRange+1.0);
+            pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
             break;
           }
-          case BlendCompositeOp:
+          case MultiplyCompositeOp:
           {
-            CompositePixelInfoBlend(&source,source_dissolve,&destination,
-              destination_dissolve,&composite);
+            pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case ThresholdCompositeOp:
+          case OutCompositeOp:
+          case SrcOutCompositeOp:
           {
-            CompositeThreshold(&source,&destination,threshold,amount,&composite);
+            pixel=gamma*(Sa*Sc*(1.0-Da));
             break;
           }
-          case ModulateCompositeOp:
+          case OverCompositeOp:
+          case SrcOverCompositeOp:
           {
-            double
-              blue,
-              green,
-              red;
-
-            ssize_t
-              offset;
-
-            if (source.alpha == TransparentAlpha)
-              break;
-            offset=(ssize_t) (GetPixelInfoIntensity(&source)-midpoint);
-            if (offset == 0)
-              break;
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            brightness+=(0.01*percent_brightness*offset)/midpoint;
-            saturation*=0.01*percent_saturation;
-            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
-            composite.red=red;
-            composite.green=green;
-            composite.blue=blue;
+            pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
             break;
           }
-          case HueCompositeOp:
+          case OverlayCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            if ((2.0*Dca) < Da)
               {
-                composite=source;
+                pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
+                  (1.0-Da));
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&hue,&sans,&sans);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
+              Sca*(1.0-Da));
             break;
           }
-          case SaturateCompositeOp:
+          case PegtopLightCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            /*
+              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
+
+              http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
+            */
+            if (fabs(Da) < MagickEpsilon)
               {
-                composite=source;
+                pixel=QuantumRange*gamma*(Sca);
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&sans,&saturation,
-              &sans);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
+              Da)+Dca*(1.0-Sa));
             break;
           }
-          case LuminizeCompositeOp:
+          case PinLightCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            /*
+              PinLight: A Photoshop 7 composition method
+              http://www.simplefilter.de/en/basics/mixmods.html
+
+                f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
+            */
+            if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
+              {
+                pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
+                break;
+              }
+            if ((Dca*Sa) > (2.0*Sca*Da))
               {
-                composite=source;
+                pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&sans,&sans,
-              &brightness);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
             break;
           }
-          case ColorizeCompositeOp:
+          case PlusCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
+            break;
+          }
+          case SaturateCompositeOp:
+          {
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
               {
-                composite=source;
+                pixel=Sc;
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&sans,
-              &sans,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&hue,&saturation,
-              &sans);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
+              GetPixelBlue(image,q),&hue,&saturation,&brightness);
+            CompositeHSB(GetPixelRed(composite_image,p),
+              GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
+              &sans,&saturation,&sans);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case CopyRedCompositeOp:
-          case CopyCyanCompositeOp:
+          case ScreenCompositeOp:
           {
-            composite.red=source.red;
+            /*
+              Screen:  a negated multiply:
+
+                f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
+            */
+            pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
             break;
           }
-          case CopyGreenCompositeOp:
-          case CopyMagentaCompositeOp:
+          case SoftLightCompositeOp:
           {
-            composite.green=source.green;
+            /*
+              Refer to the March 2009 SVG specification.
+            */
+            if ((2.0*Sca) < Sa)
+              {
+                pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
+                  Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
+              {
+                pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
+                  (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
+                  Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
+              (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case CopyBlueCompositeOp:
-          case CopyYellowCompositeOp:
+          case ThresholdCompositeOp:
           {
-            composite.blue=source.blue;
+            MagickRealType
+              delta;
+
+            delta=Sc-Dc;
+            if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
+              {
+                pixel=gamma*Dc;
+                break;
+              }
+            pixel=gamma*(Dc+delta*amount);
             break;
           }
-          case CopyOpacityCompositeOp:
+          case VividLightCompositeOp:
           {
-            if (source.matte == MagickFalse)
+            /*
+              VividLight: A Photoshop 7 composition method.  See
+              http://www.simplefilter.de/en/basics/mixmods.html.
+
+                f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
+            */
+            if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if ((2.0*Sca) <= Sa)
               {
-                composite.alpha=(MagickRealType) GetPixelInfoIntensity(&source);
+                pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
+                  (1.0-Da)+Dca*(1.0-Sa));
                 break;
               }
-            composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
             break;
           }
-          case CopyBlackCompositeOp:
+          case XorCompositeOp:
           {
-            if (source.colorspace != CMYKColorspace)
-              ConvertRGBToCMYK(&source);
-            composite.black=source.black;
+            pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
             break;
           }
-          case BlurCompositeOp:
-          case DisplaceCompositeOp:
-          case DistortCompositeOp:
+          default:
           {
-            composite=source;
+            pixel=Sc;
             break;
           }
-          default:
-            break;
         }
-        if (image->colorspace == CMYKColorspace)
-          {
-            composite.red=(MagickRealType) QuantumRange-composite.red;
-            composite.green=(MagickRealType) QuantumRange-composite.green;
-            composite.blue=(MagickRealType) QuantumRange-composite.blue;
-            composite.black=(MagickRealType) QuantumRange-composite.black;
-          }
-        SetPixelRed(image,ClampToQuantum(composite.red),q);
-        SetPixelGreen(image,ClampToQuantum(composite.green),q);
-        SetPixelBlue(image,ClampToQuantum(composite.blue),q);
-        if (image->colorspace == CMYKColorspace)
-          SetPixelBlack(image,ClampToQuantum(composite.black),q);
-        SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
+        q[i]=ClampToQuantum(pixel);
       }
       p+=GetPixelChannels(composite_image);
-      if (p >= (pixels+composite_image->columns*GetPixelChannels(composite_image)))
+      channels=GetPixelChannels(composite_image);
+      if (p >= (pixels+channels*composite_image->columns))
         p=pixels;
       q+=GetPixelChannels(image);
     }
@@ -3263,18 +2222,18 @@ MagickBooleanType composite_channels;
 %
 %  The format of the TextureImage method is:
 %
-%      MagickBooleanType TextureImage(Image *image,const Image *texture,
+%      MagickBooleanType TextureImage(Image *image,const Image *texture_image,
 %        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o texture: This image is the texture to layer on the background.
+%    o texture_image: This image is the texture to layer on the background.
 %
 */
-MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
-  ExceptionInfo *exception)
+MagickExport MagickBooleanType TextureImage(Image *image,
+  const Image *texture_image,ExceptionInfo *exception)
 {
 #define TextureImageTag  "Texture/Image"
 
@@ -3292,36 +2251,37 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(image->signature == MagickSignature);
-  if (texture == (const Image *) NULL)
+  if (texture_image == (const Image *) NULL)
     return(MagickFalse);
-  (void) SetImageVirtualPixelMethod(texture,TileVirtualPixelMethod);
+  (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
   status=MagickTrue;
   if ((image->compose != CopyCompositeOp) &&
       ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
-       (texture->matte != MagickFalse)))
+       (texture_image->matte != MagickFalse)))
     {
       /*
         Tile texture onto the image background.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+      #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
 #endif
-      for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture->rows)
+      for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
       {
         register ssize_t
           x;
 
         if (status == MagickFalse)
           continue;
-        for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
+        for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
         {
           MagickBooleanType
             thread_status;
 
-          thread_status=CompositeImage(image,image->compose,texture,x+
-            texture->tile_offset.x,y+texture->tile_offset.y,exception);
+          thread_status=CompositeImage(image,image->compose,texture_image,x+
+            texture_image->tile_offset.x,y+texture_image->tile_offset.y,
+            exception);
           if (thread_status == MagickFalse)
             {
               status=thread_status;
@@ -3351,9 +2311,9 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
   */
   status=MagickTrue;
   image_view=AcquireCacheView(image);
-  texture_view=AcquireCacheView(texture);
+  texture_view=AcquireCacheView(texture_image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+  #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3375,34 +2335,47 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
 
     if (status == MagickFalse)
       continue;
-    pixels=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);
+    pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
+      (y+texture_image->tile_offset.y) % texture_image->rows,
+      texture_image->columns,1,exception);
+    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
     if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
+    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
     {
       register ssize_t
-        i;
+        j;
 
       p=pixels;
-      width=texture->columns;
+      width=texture_image->columns;
       if ((x+(ssize_t) width) > (ssize_t) image->columns)
         width=image->columns-x;
-      for (i=0; i < (ssize_t) width; i++)
+      for (j=0; j < (ssize_t) width; j++)
       {
-        SetPixelRed(image,GetPixelRed(texture,p),q);
-        SetPixelGreen(image,GetPixelGreen(texture,p),q);
-        SetPixelBlue(image,GetPixelBlue(texture,p),q);
-        SetPixelAlpha(image,GetPixelAlpha(texture,p),q);
-        if ((image->colorspace == CMYKColorspace)  &&
-            (texture->colorspace == CMYKColorspace))
-          SetPixelBlack(image,GetPixelBlack(texture,p),q);
-        p+=GetPixelChannels(texture);
+        register ssize_t
+          i;
+
+        for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
+        {
+          PixelChannel
+            channel;
+
+          PixelTrait
+            texture_traits,
+            traits;
+
+          channel=GetPixelChannelMapChannel(texture_image,i);
+          texture_traits=GetPixelChannelMapTraits(texture_image,channel);
+          traits=GetPixelChannelMapTraits(image,channel);
+          if ((traits == UndefinedPixelTrait) ||
+              (texture_traits == UndefinedPixelTrait))
+            continue;
+          SetPixelChannel(image,channel,p[i],q);
+        }
+        p+=GetPixelChannels(texture_image);
         q+=GetPixelChannels(image);
       }
     }