]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/composite.c
sigmoidal-contrast: prevent argument out of range and remove unnecessary ClampToQuantum
[imagemagick] / MagickCore / composite.c
index 4500683c8f81d2c517f1c81b3808adc29c90d30b..788bae850f048999970b5d918d906bc6e725938f 100644 (file)
@@ -72,6 +72,8 @@
 #include "MagickCore/resource_.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/thread-private.h"
+#include "MagickCore/threshold.h"
+#include "MagickCore/token.h"
 #include "MagickCore/utility.h"
 #include "MagickCore/utility-private.h"
 #include "MagickCore/version.h"
 %  The format of the CompositeImage method is:
 %
 %      MagickBooleanType CompositeImage(Image *image,
-%        const CompositeOperator compose,Image *composite_image,
-%        const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
+%        const Image *composite_image,const CompositeOperator compose,
+%        const MagickBooleanType clip_to_self,const ssize_t x_offset,
+%        const ssize_t y_offset,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the destination image, modified by he composition
 %
+%    o composite_image: the composite (source) image.
+%
 %    o compose: This operator affects how the composite is applied to
 %      the image.  The operators and how they are utilized are listed here
 %      http://www.w3.org/TR/SVG12/#compositing.
 %
-%    o composite_image: the composite (source) image.
+%    o clip_to_self: set to MagickTrue to limit composition to area composed.
 %
 %    o x_offset: the column offset of the composited image.
 %
 %        Compose methods needing such arguments include "BlendCompositeOp" and
 %        "DisplaceCompositeOp".
 %
-%    o "compose:outside-overlay"
-%        Modify how the composition is to effect areas not directly covered
-%        by the 'composite_image' at the offset given.  Normally this is
-%        dependant on the 'compose' method, especially Duff-Porter methods.
-%
-%        If set to "false" then disable all normal handling of pixels not
-%        covered by the composite_image.  Typically used for repeated tiling
-%        of the composite_image by the calling API.
-%
-%        Previous to IM v6.5.3-3  this was called "modify-outside-overlay"
-%
 %    o exception: return any errors or warnings in this structure.
 %
 */
 
-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.
+   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
+      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.
+      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.
 
-   The compose functions defined is just simplifications of the above
-   formula on a case by case bases.
+   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 defines that Mathematical Composition
+   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
+    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
+    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)
+    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
@@ -195,1378 +177,386 @@ static inline double MagickMax(const double x,const double y)
        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)
+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=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);
+  if (x < y)
+    return(x);
+  return(y);
 }
 
-static inline MagickRealType Darken(const MagickRealType p,
-  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
+static inline double MagickMax(const double x,const double y)
 {
-  if (p < q)
-    return(MagickOver_(p,alpha,q,beta));  /* src-over */
-  return(MagickOver_(q,beta,p,alpha));    /* dst-over */
+  if (x > y)
+    return(x);
+  return(y);
 }
 
-static inline void CompositeDarken(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
+static inline double ConvertHueToRGB(double m1,
+  double m2,double hue)
 {
-  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);
+  if (hue < 0.0)
+    hue+=1.0;
+  if (hue > 1.0)
+    hue-=1.0;
+  if ((6.0*hue) < 1.0)
+    return(m1+6.0*(m2-m1)*hue);
+  if ((2.0*hue) < 1.0)
+    return(m2);
+  if ((3.0*hue) < 2.0)
+    return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
+  return(m1);
 }
 
-static inline void CompositeDarkenIntensity(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
+static void HCLComposite(const double hue,const double chroma,const double luma,
+  double *red,double *green,double *blue)
 {
-  MagickRealType
-    Da,
-    Sa;
+  double
+    b,
+    c,
+    g,
+    h,
+    m,
+    r,
+    x,
+    z;
 
   /*
-    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.
+    Convert HCL to RGB colorspace.
   */
-  if (image->channel_mask != DefaultChannels)
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  h=6.0*hue;
+  c=chroma;
+  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
+  r=0.0;
+  g=0.0;
+  b=0.0;
+  if ((0.0 <= h) && (h < 1.0))
     {
-      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;
+      r=c;
+      g=x;
     }
-  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)
-{
+  else
+    if ((1.0 <= h) && (h < 2.0))
+      {
+        r=x;
+        g=c;
+      }
+    else
+      if ((2.0 <= h) && (h < 3.0))
+        {
+          g=c;
+          b=x;
+        }
+      else
+        if ((3.0 <= h) && (h < 4.0))
+          {
+            g=x;
+            b=c;
+          }
+        else
+          if ((4.0 <= h) && (h < 5.0))
+            {
+              r=x;
+              b=c;
+            }
+          else
+            if ((5.0 <= h) && (h < 6.0))
+              {
+                r=c;
+                b=x;
+              }
+  m=luma-(0.298839*r+0.586811*g+0.114350*b);
   /*
-    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.
+    Choose saturation strategy to clip it into the RGB cube; hue and luma are
+    preserved and chroma may be changed.
   */
-  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)
+  z=1.0;
+  if (m < 0.0)
     {
-      /*
-        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;
+      z=luma/(luma-m);
+      m=0.0;
     }
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Exclusion(QuantumScale*p->black*Sa,Sa,
-      QuantumScale*q->black*Da,Da);
-}
-
-static MagickRealType HardLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  if ((2.0*Sca) < Sa)
-    return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeHardLight(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*HardLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
+  else
+    if (m+c > 1.0)
+      {
+        z=(1.0-luma)/(m+c-luma);
+        m=1.0-z*c;
+      }
+  *red=QuantumRange*(z*r+m);
+  *green=QuantumRange*(z*g+m);
+  *blue=QuantumRange*(z*b+m);
 }
 
-static void CompositeHSB(const MagickRealType red,const MagickRealType green,
-  const MagickRealType blue,double *hue,double *saturation,double *brightness)
+static void CompositeHCL(const double red,const double green,const double blue,
+  double *hue,double *chroma,double *luma)
 {
-  MagickRealType
-    delta,
+  double
+    b,
+    c,
+    g,
+    h,
     max,
-    min;
+    r;
 
   /*
-    Convert RGB to HSB colorspace.
+    Convert RGB to HCL colorspace.
   */
   assert(hue != (double *) NULL);
-  assert(saturation != (double *) NULL);
-  assert(brightness != (double *) NULL);
-  max=(red > green ? red : green);
-  if (blue > max)
-    max=blue;
-  min=(red < green ? red : green);
-  if (blue < min)
-    min=blue;
-  *hue=0.0;
-  *saturation=0.0;
-  *brightness=(double) (QuantumScale*max);
-  if (fabs(max) < MagickEpsilon)
-    return;
-  *saturation=(double) (1.0-min/max);
-  delta=max-min;
-  if (fabs(delta) < MagickEpsilon)
-    return;
-  if (fabs(red-max) < MagickEpsilon)
-    *hue=(double) ((green-blue)/delta);
+  assert(chroma != (double *) NULL);
+  assert(luma != (double *) NULL);
+  r=red;
+  g=green;
+  b=blue;
+  max=MagickMax(r,MagickMax(g,b));
+  c=max-(double) MagickMin(r,MagickMin(g,b));
+  h=0.0;
+  if (c == 0)
+    h=0.0;
   else
-    if (fabs(green-max) < MagickEpsilon)
-      *hue=(double) (2.0+(blue-red)/delta);
+    if (red == max)
+      h=fmod(6.0+(g-b)/c,6.0);
     else
-      if (fabs(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)
-{
-  MagickRealType
-    gamma;
-
-  /*
-    Lighten is also equvalent to a 'Maximum' method OR a greyscale version of a
-    binary 'And' OR the 'Union' of pixel sets.
-  */
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        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);
-      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)
-    {
-      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;
+      if (green == max)
+        h=((b-r)/c)+2.0;
+      else
+        if (blue == max)
+          h=((r-g)/c)+4.0;
+  *hue=(h/6.0);
+  *chroma=QuantumScale*c;
+  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
 }
 
-static inline void CompositeLinearDodge(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
+static MagickBooleanType CompositeOverImage(Image *image,
+  const Image *composite_image,const MagickBooleanType clip_to_self,
+  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=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);
-}
+#define CompositeImageTag  "Composite/Image"
 
+  CacheView
+    *composite_view,
+    *image_view;
 
-static inline MagickRealType LinearBurn(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    LinearBurn: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
+  MagickBooleanType
+    status;
 
-      f(Sc,Dc) = Sc + Dc - 1
-  */
-  return(Sca+Dca-Sa*Da);
-}
+  MagickOffsetType
+    progress;
 
-static inline void CompositeLinearBurn(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*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);
-}
+  ssize_t
+    y;
 
-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:
-
-      f(Sc,Dc) = Dc + 2*Sc - 1
+    Composite image.
   */
-  return((Sca-Sa)*Da+Sca+Dca);
-}
-
-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.
+  status=MagickTrue;
+  progress=0;
+  composite_view=AcquireVirtualCacheView(composite_image,exception);
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    dynamic_number_threads(image,image->columns,image->rows,1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const Quantum
+      *pixels;
 
-       A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
+    register const Quantum
+      *restrict p;
 
-    Applying the SVG transparency formula (see above), we get...
+    register Quantum
+      *restrict q;
 
-     Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
+    register ssize_t
+      x;
 
-     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);
-}
+    size_t
+      channels;
 
-static inline void CompositeMathematics(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,const GeometryInfo *args,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha; /* ??? - AT */
-  Da=QuantumScale*q->alpha;
-  if (image->channel_mask != DefaultChannels)
+    if (status == MagickFalse)
+      continue;
+    if (clip_to_self != 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=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);
-}
-
-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.
+      double
+        alpha,
+        Da,
+        Dc,
+        gamma,
+        Sa,
+        Sc;
 
-    As such the removal of the 'sync' flag, is still a usful convention.
+      register ssize_t
+        i;
 
-    The CompositePixelInfoPlus() function is defined in
-    "composite-private.h" so it can also be used for Image Blending.
-  */
-  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))
-{
-  /*
-    Minus Source from Destination
-
-      f(Sc,Dc) = Sc - Dc
-  */
-  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);
-}
-
-static inline MagickRealType ModulusAdd(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
-{
-  MagickRealType
-    pixel;
-
-  pixel=p+q;
-  if (pixel > QuantumRange)
-    pixel-=(QuantumRange+1.0);
-  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
-}
-
-static inline void CompositeModulusAdd(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        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;
-
-  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));
-}
-
-static inline void CompositeModulusSubtract(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels,
-      */
-      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*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);
-}
-
-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 (clip_to_self != 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];
 
-static inline void CompositeMultiply(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)
-    {
+          /*
+            Virtual composite:
+              Sc: source color.
+              Dc: destination color.
+          */
+          if (GetPixelMask(image,q) != 0)
+            {
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          (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=GetPixelChannelChannel(image,i);
+            traits=GetPixelChannelTraits(image,channel);
+            composite_traits=GetPixelChannelTraits(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=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;
+      if (GetPixelMask(composite_image,p) != 0)
+        {
+          p+=GetPixelChannels(composite_image);
+          channels=GetPixelChannels(composite_image);
+          if (p >= (pixels+channels*composite_image->columns))
+            p=pixels;
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      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=GetPixelChannelChannel(image,i);
+        traits=GetPixelChannelTraits(image,channel);
+        composite_traits=GetPixelChannelTraits(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=(double) GetPixelChannel(composite_image,channel,p);
+        Dc=(double) q[i];
+        gamma=MagickEpsilonReciprocal(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);
     }
-  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);
-}
-
-#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
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
 
-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);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+        #pragma omp critical (MagickCore_CompositeImage)
 #endif
-}
-
-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.
-
-    f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
-
-    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));
-}
-
-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);
-}
-
-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
-
-    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);
-}
-
-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);
-}
-
-static inline MagickRealType Screen(const MagickRealType Sca,
-  const MagickRealType Dca)
-{
-  /*
-    Screen:  A negated multiply
-      f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
-  */
-  return(Sca+Dca-Sca*Dca);
-}
-
-static inline void CompositeScreen(const 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*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;
-    }
+        proceed=SetImageProgress(image,CompositeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
   }
+  composite_view=DestroyCacheView(composite_view);
+  image_view=DestroyCacheView(image_view);
+  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)
+  const Image *composite,const CompositeOperator compose,
+  const MagickBooleanType clip_to_self,const ssize_t x_offset,
+  const ssize_t y_offset,ExceptionInfo *exception)
 {
 #define CompositeImageTag  "Composite/Image"
 
@@ -1574,31 +564,25 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     *composite_view,
     *image_view;
 
-  const char
-    *value;
-
-  double
-    sans;
-
   GeometryInfo
     geometry_info;
 
   Image
+    *composite_image,
     *destination_image;
 
   MagickBooleanType
-    modify_outside_overlay,
     status;
 
   MagickOffsetType
     progress;
 
-  MagickRealType
+  double
     amount,
     destination_dissolve,
     midpoint,
-    percent_brightness,
-    percent_saturation,
+    percent_luma,
+    percent_chroma,
     source_dissolve,
     threshold;
 
@@ -1608,42 +592,34 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
   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);
+  assert(composite!= (Image *) NULL);
+  assert(composite->signature == MagickSignature);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  composite_image=CloneImage(composite,0,0,MagickTrue,exception);
+  if (composite_image == (const Image *) NULL)
+    return(MagickFalse);
+  (void) SetImageColorspace(composite_image,image->colorspace,exception);
+  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
+    {
+      status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
+        y_offset,exception);
+      composite_image=DestroyImage(composite_image);
+      return(status);
+    }
   destination_image=(Image *) NULL;
   amount=0.5;
   destination_dissolve=1.0;
-  modify_outside_overlay=MagickFalse;
-  percent_brightness=100.0;
-  percent_saturation=100.0;
+  percent_luma=100.0;
+  percent_chroma=100.0;
   source_dissolve=1.0;
   threshold=0.05f;
   switch (compose)
   {
-    case ClearCompositeOp:
-    case DstAtopCompositeOp:
-    case DstInCompositeOp:
-    case InCompositeOp:
-    case OutCompositeOp:
-    case SrcCompositeOp:
-    case SrcInCompositeOp:
-    case SrcOutCompositeOp:
-    {
-      /*
-        Modify destination outside the overlaid region.
-      */
-      modify_outside_overlay=MagickTrue;
-      break;
-    }
     case CopyCompositeOp:
     {
       if ((x_offset < 0) || (y_offset < 0))
@@ -1653,10 +629,11 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
         break;
       status=MagickTrue;
-      image_view=AcquireCacheView(image);
-      composite_view=AcquireCacheView(composite_image);
+      composite_view=AcquireVirtualCacheView(composite_image,exception);
+      image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp parallel for schedule(dynamic,4) shared(status)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        dynamic_number_threads(image,image->columns,image->rows,1)
 #endif
       for (y=0; y < (ssize_t) composite_image->rows; y++)
       {
@@ -1685,12 +662,32 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
           }
         for (x=0; x < (ssize_t) composite_image->columns; x++)
         {
-          SetPixelRed(image,GetPixelRed(composite_image,p),q);
-          SetPixelGreen(image,GetPixelGreen(composite_image,p),q);
-          SetPixelBlue(image,GetPixelBlue(composite_image,p),q);
-          SetPixelAlpha(image,GetPixelAlpha(composite_image,p),q);
-          if (image->colorspace == CMYKColorspace)
-            SetPixelBlack(image,GetPixelBlack(composite_image,p),q);
+          register ssize_t
+            i;
+
+          if (GetPixelMask(composite_image,p) != 0)
+            {
+              p+=GetPixelChannels(composite_image);
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          for (i=0; i < (ssize_t) GetPixelChannels(composite_image); i++)
+          {
+            PixelChannel
+              channel;
+
+            PixelTrait
+              composite_traits,
+              traits;
+
+            channel=GetPixelChannelChannel(composite_image,i);
+            composite_traits=GetPixelChannelTraits(composite_image,channel);
+            traits=GetPixelChannelTraits(image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            SetPixelChannel(image,channel,p[i],q);
+          }
           p+=GetPixelChannels(composite_image);
           q+=GetPixelChannels(image);
         }
@@ -1703,7 +700,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
               proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp critical (MagickCore_CompositeImage)
+            #pragma omp critical (MagickCore_CompositeImage)
 #endif
             proceed=SetImageProgress(image,CompositeImageTag,
               (MagickOffsetType) y,image->rows);
@@ -1713,18 +710,19 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       }
       composite_view=DestroyCacheView(composite_view);
       image_view=DestroyCacheView(image_view);
+      composite_image=DestroyImage(composite_image);
       return(status);
     }
-    case CopyOpacityCompositeOp:
+    case CopyAlphaCompositeOp:
     case ChangeMaskCompositeOp:
+    case IntensityCompositeOp:
     {
       /*
         Modify destination outside the overlaid region and require an alpha
         channel to exist, to add transparency.
       */
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait != BlendPixelTrait)
         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      modify_outside_overlay=MagickTrue;
       break;
     }
     case BlurCompositeOp:
@@ -1733,10 +731,13 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         *composite_view,
         *destination_view;
 
+      const char
+        *value;
+
       PixelInfo
         pixel;
 
-      MagickRealType
+      double
         angle_range,
         angle_start,
         height,
@@ -1749,39 +750,52 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         blur;
 
       /*
+        Blur Image by resampling.
+
         Blur Image dictated by an overlay gradient map: X = red_channel;
           Y = green_channel; compose:args =  x_scale[,y_scale[,angle]].
       */
       destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
         exception);
       if (destination_image == (Image *) NULL)
-        return(MagickFalse);
+        {
+          composite_image=DestroyImage(composite_image);
+          return(MagickFalse);
+        }
       /*
-        Determine the horizontal and vertical maximim blur.
+        Gather the maximum blur sigma values from user.
       */
       SetGeometryInfo(&geometry_info);
       flags=NoValue;
       value=GetImageArtifact(composite_image,"compose:args");
       if (value != (char *) NULL)
         flags=ParseGeometry(value,&geometry_info);
-      if ((flags & WidthValue) == 0 )
-        {
+      if ((flags & WidthValue) == 0 ) {
+          (void) ThrowMagickException(exception,GetMagickModule(),
+               OptionWarning,"InvalidSetting","'%s' '%s'",
+               "compose:args",value);
+          composite_image=DestroyImage(composite_image);
           destination_image=DestroyImage(destination_image);
           return(MagickFalse);
         }
-      width=geometry_info.rho;
-      height=geometry_info.sigma;
-      blur.x1=geometry_info.rho;
+      /*
+        Users input sigma now needs to be converted to the EWA ellipse size.
+        The filter defaults to a sigma of 0.5 so to make this match the
+        users input the ellipse size needs to be doubled.
+      */
+      width=height=geometry_info.rho*2.0;
+      if ((flags & HeightValue) != 0 )
+        height=geometry_info.sigma*2.0;
+
+      /* default the unrotated ellipse width and height axis vectors */
+      blur.x1=width;
       blur.x2=0.0;
       blur.y1=0.0;
-      blur.y2=geometry_info.sigma;
-      angle_start=0.0;
-      angle_range=0.0;
-      if ((flags & HeightValue) == 0)
-        blur.y2=blur.x1;
+      blur.y2=height;
+      /* rotate vectors if a rotation angle is given */
       if ((flags & XValue) != 0 )
         {
-          MagickRealType
+          double
             angle;
 
           angle=DegreesToRadians(geometry_info.xi);
@@ -1790,18 +804,32 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
           blur.y1=(-height*sin(angle));
           blur.y2=height*cos(angle);
         }
+      /* Otherwise lets set a angle range and calculate in the loop */
+      angle_start=0.0;
+      angle_range=0.0;
       if ((flags & YValue) != 0 )
         {
           angle_start=DegreesToRadians(geometry_info.xi);
           angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
         }
       /*
-        Blur Image by resampling.
+        Set up a gaussian cylindrical filter for EWA Bluring.
+
+        As the minimum ellipse radius of support*1.0 the EWA algorithm
+        can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
+        This means that even 'No Blur' will be still a little blurry!
+
+        The solution (as well as the problem of preventing any user
+        expert filter settings, is to set our own user settings, then
+        restore them afterwards.
       */
       resample_filter=AcquireResampleFilter(image,exception);
-      SetResampleFilter(resample_filter,CubicFilter,2.0);
-      destination_view=AcquireCacheView(destination_image);
-      composite_view=AcquireCacheView(composite_image);
+      SetResampleFilter(resample_filter,GaussianFilter);
+
+      /* do the variable blurring of each pixel in image */
+      GetPixelInfo(image,&pixel);
+      composite_view=AcquireVirtualCacheView(composite_image,exception);
+      destination_view=AcquireAuthenticCacheView(destination_image,exception);
       for (y=0; y < (ssize_t) composite_image->rows; y++)
       {
         MagickBooleanType
@@ -1833,7 +861,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
             }
           if (fabs(angle_range) > MagickEpsilon)
             {
-              MagickRealType
+              double
                 angle;
 
               angle=angle_start+angle_range*QuantumScale*
@@ -1843,13 +871,20 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
               blur.y1=(-height*sin(angle));
               blur.y2=height*cos(angle);
             }
-          ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
-            GetPixelRed(composite_image,p),blur.y1*QuantumScale*
-            GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
-            GetPixelRed(composite_image,p),blur.y2*QuantumScale*
-            GetPixelGreen(composite_image,p));
+#if 0
+          if ( x == 10 && y == 60 ) {
+            fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",
+                blur.x1, blur.x2, blur.y1, blur.y2);
+            fprintf(stderr, "scaled by=%lf,%lf\n",
+                QuantumScale*GetPixelRed(p), QuantumScale*GetPixelGreen(p));
+#endif
+          ScaleResampleFilter(resample_filter,
+            blur.x1*QuantumScale*GetPixelRed(composite_image,p),
+            blur.y1*QuantumScale*GetPixelGreen(composite_image,p),
+            blur.x2*QuantumScale*GetPixelRed(composite_image,p),
+            blur.y2*QuantumScale*GetPixelGreen(composite_image,p) );
           (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
-            (double) y_offset+y,&pixel);
+            (double) y_offset+y,&pixel,exception);
           SetPixelInfoPixel(destination_image,&pixel,q);
           p+=GetPixelChannels(composite_image);
           q+=GetPixelChannels(destination_image);
@@ -1861,6 +896,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       resample_filter=DestroyResampleFilter(resample_filter);
       composite_view=DestroyCacheView(composite_view);
       destination_view=DestroyCacheView(destination_view);
+      composite_image=DestroyImage(composite_image);
       composite_image=destination_image;
       break;
     }
@@ -1872,10 +908,13 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         *destination_view,
         *image_view;
 
+      const char
+        *value;
+
       PixelInfo
         pixel;
 
-      MagickRealType
+      double
         horizontal_scale,
         vertical_scale;
 
@@ -1891,7 +930,10 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
         exception);
       if (destination_image == (Image *) NULL)
-        return(MagickFalse);
+        {
+          composite_image=DestroyImage(composite_image);
+          return(MagickFalse);
+        }
       SetGeometryInfo(&geometry_info);
       flags=NoValue;
       value=GetImageArtifact(composite_image,"compose:args");
@@ -1901,14 +943,14 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         {
           if ((flags & AspectValue) == 0)
             {
-              horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
+              horizontal_scale=(double) (composite_image->columns-1.0)/
                 2.0;
-              vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
+              vertical_scale=(double) (composite_image->rows-1.0)/2.0;
             }
           else
             {
-              horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
-              vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
+              horizontal_scale=(double) (image->columns-1.0)/2.0;
+              vertical_scale=(double) (image->rows-1.0)/2.0;
             }
         }
       else
@@ -1939,29 +981,29 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
            default = center of overlay image
            arg flag '!' = locations/percentage relative to background image
       */
-      center.x=(MagickRealType) x_offset;
-      center.y=(MagickRealType) y_offset;
+      center.x=(double) x_offset;
+      center.y=(double) y_offset;
       if (compose == DistortCompositeOp)
         {
           if ((flags & XValue) == 0)
             if ((flags & AspectValue) == 0)
-              center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
+              center.x=(double) x_offset+(composite_image->columns-1)/
                 2.0;
             else
-              center.x=((MagickRealType) image->columns-1)/2.0;
+              center.x=((double) image->columns-1)/2.0;
           else
             if ((flags & AspectValue) == 0)
-              center.x=(MagickRealType) x_offset+geometry_info.xi;
+              center.x=(double) x_offset+geometry_info.xi;
             else
               center.x=geometry_info.xi;
           if ((flags & YValue) == 0)
             if ((flags & AspectValue) == 0)
-              center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
+              center.y=(double) y_offset+(composite_image->rows-1)/2.0;
             else
-              center.y=((MagickRealType) image->rows-1)/2.0;
+              center.y=((double) image->rows-1)/2.0;
           else
             if ((flags & AspectValue) == 0)
-              center.y=(MagickRealType) y_offset+geometry_info.psi;
+              center.y=(double) y_offset+geometry_info.psi;
             else
               center.y=geometry_info.psi;
         }
@@ -1970,9 +1012,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         displacement/distortion map.  -- Like a lens...
       */
       GetPixelInfo(image,&pixel);
-      image_view=AcquireCacheView(image);
-      destination_view=AcquireCacheView(destination_image);
-      composite_view=AcquireCacheView(composite_image);
+      image_view=AcquireVirtualCacheView(image,exception);
+      composite_view=AcquireVirtualCacheView(composite_image,exception);
+      destination_view=AcquireAuthenticCacheView(destination_image,exception);
       for (y=0; y < (ssize_t) composite_image->rows; y++)
       {
         MagickBooleanType
@@ -2006,11 +1048,11 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
             Displace the offset.
           */
           offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
-            (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
+            (((double) QuantumRange+1.0)/2.0)))/(((double)
             QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
             x : 0);
           offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
-            (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
+            (((double) QuantumRange+1.0)/2.0)))/(((double)
             QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
             y : 0);
           (void) InterpolatePixelInfo(image,image_view,
@@ -2019,9 +1061,8 @@ 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=(double) QuantumRange*(1.0-(1.0-QuantumScale*
+            pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
           SetPixelInfoPixel(destination_image,&pixel,q);
           p+=GetPixelChannels(composite_image);
           q+=GetPixelChannels(destination_image);
@@ -2033,11 +1074,15 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       destination_view=DestroyCacheView(destination_view);
       composite_view=DestroyCacheView(composite_view);
       image_view=DestroyCacheView(image_view);
+      composite_image=DestroyImage(composite_image);
       composite_image=destination_image;
       break;
     }
     case DissolveCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Geometry arguments to dissolve factors.
       */
@@ -2058,17 +1103,22 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
             destination_dissolve=geometry_info.sigma/100.0;
           if ((destination_dissolve-MagickEpsilon) < 0.0)
             destination_dissolve=0.0;
-          modify_outside_overlay=MagickTrue;
+       /* posible speed up?  -- from IMv6 update
+          clip_to_self=MagickFalse;
           if ((destination_dissolve+MagickEpsilon) > 1.0 )
             {
               destination_dissolve=1.0;
-              modify_outside_overlay=MagickFalse;
+              clip_to_self=MagickTrue;
             }
+        */
         }
       break;
     }
     case BlendCompositeOp:
     {
+      const char
+        *value;
+
       value=GetImageArtifact(composite_image,"compose:args");
       if (value != (char *) NULL)
         {
@@ -2077,14 +1127,14 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
           destination_dissolve=1.0-source_dissolve;
           if ((flags & SigmaValue) != 0)
             destination_dissolve=geometry_info.sigma/100.0;
-          modify_outside_overlay=MagickTrue;
-          if ((destination_dissolve+MagickEpsilon) > 1.0)
-            modify_outside_overlay=MagickFalse;
         }
       break;
     }
     case MathematicsCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Just collect the values from "compose:args", setting.
         Unused values are set to zero automagically.
@@ -2101,21 +1151,27 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case ModulateCompositeOp:
     {
+      const char
+        *value;
+
       /*
-        Determine the brightness and saturation scale.
+        Determine the luma and chroma scale.
       */
       value=GetImageArtifact(composite_image,"compose:args");
       if (value != (char *) NULL)
         {
           flags=ParseGeometry(value,&geometry_info);
-          percent_brightness=geometry_info.rho;
+          percent_luma=geometry_info.rho;
           if ((flags & SigmaValue) != 0)
-            percent_saturation=geometry_info.sigma;
+            percent_chroma=geometry_info.sigma;
         }
       break;
     }
     case ThresholdCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Determine the amount and threshold.
       */
@@ -2134,19 +1190,17 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     default:
       break;
   }
-  value=GetImageArtifact(composite_image,"compose:outside-overlay");
-  if (value != (const char *) NULL)
-    modify_outside_overlay=IsMagickTrue(value);
   /*
     Composite image.
   */
   status=MagickTrue;
   progress=0;
-  midpoint=((MagickRealType) QuantumRange+1.0)/2;
-  image_view=AcquireCacheView(image);
-  composite_view=AcquireCacheView(composite_image);
+  midpoint=((double) QuantumRange+1.0)/2;
+  composite_view=AcquireVirtualCacheView(composite_image,exception);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #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) \
+    dynamic_number_threads(image,image->columns,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2154,9 +1208,16 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       *pixels;
 
     double
-      brightness,
+      blue,
+      luma,
+      green,
       hue,
-      saturation;
+      red,
+      chroma;
+
+    PixelInfo
+      destination_pixel,
+      source_pixel;
 
     register const Quantum
       *restrict p;
@@ -2167,11 +1228,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     register ssize_t
       x;
 
-MagickBooleanType composite_channels;
-
     if (status == MagickFalse)
       continue;
-    if (modify_outside_overlay == MagickFalse)
+    if (clip_to_self != MagickFalse)
       {
         if (y < y_offset)
           continue;
@@ -2203,11 +1262,29 @@ MagickBooleanType composite_channels;
         continue;
       }
     hue=0.0;
-    saturation=0.0;
-    brightness=0.0;
+    chroma=0.0;
+    luma=0.0;
+    GetPixelInfo(image,&destination_pixel);
+    GetPixelInfo(composite_image,&source_pixel);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if (modify_outside_overlay == MagickFalse)
+      double
+        alpha,
+        Da,
+        Dc,
+        Dca,
+        gamma,
+        Sa,
+        Sc,
+        Sca;
+
+      register ssize_t
+        i;
+
+      size_t
+        channels;
+
+      if (clip_to_self != MagickFalse)
         {
           if (x < x_offset)
             {
@@ -2217,1010 +1294,1023 @@ MagickBooleanType composite_channels;
           if ((x-x_offset) >= (ssize_t) composite_image->columns)
             break;
         }
-      composite_channels=MagickFalse;
+      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);
+          if (GetPixelMask(image,q) != 0)
+            {
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+          {
+            double
+              pixel;
+
+            PixelChannel
+              channel;
+
+            PixelTrait
+              composite_traits,
+              traits;
+
+            channel=GetPixelChannelChannel(image,i);
+            traits=GetPixelChannelTraits(image,channel);
+            composite_traits=GetPixelChannelTraits(composite_image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            switch (compose)
+            {
+              case AlphaCompositeOp:
+              case ChangeMaskCompositeOp:
+              case CopyAlphaCompositeOp:
+              case DstAtopCompositeOp:
+              case DstInCompositeOp:
+              case InCompositeOp:
+              case IntensityCompositeOp:
+              case OutCompositeOp:
+              case SrcInCompositeOp:
+              case SrcOutCompositeOp:
+              {
+                pixel=(double) q[i];
+                if (channel == AlphaPixelChannel)
+                  pixel=(double) TransparentAlpha;
+                break;
+              }
+              case ClearCompositeOp:
+              case CopyCompositeOp:
+              case ReplaceCompositeOp:
+              case SrcCompositeOp:
+              {
+                if (channel == AlphaPixelChannel)
+                  {
+                    pixel=(double) TransparentAlpha;
+                    break;
+                  }
+                pixel=0.0;
+                break;
+              }
+              case BlendCompositeOp:
+              case DissolveCompositeOp:
+              {
+                if (channel == AlphaPixelChannel)
+                  {
+                    pixel=destination_dissolve*GetPixelAlpha(composite_image,
+                      source);
+                    break;
+                  }
+                pixel=(double) source[channel];
+                break;
+              }
+              default:
+              {
+                pixel=(double) source[channel];
+                break;
+              }
+            }
+            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 AtopCompositeOp:
-        case ClearCompositeOp:
+        case BumpmapCompositeOp:
+        {
+          alpha=GetPixelIntensity(composite_image,p)*Sa;
+          break;
+        }
+        case ColorBurnCompositeOp:
         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 HardLightCompositeOp:
+        case LinearBurnCompositeOp:
+        case LinearDodgeCompositeOp:
+        case LinearLightCompositeOp:
         case MathematicsCompositeOp:
         case MinusDstCompositeOp:
         case MinusSrcCompositeOp:
         case ModulusAddCompositeOp:
         case ModulusSubtractCompositeOp:
         case MultiplyCompositeOp:
-        case NoCompositeOp:
-        case OutCompositeOp:
-        case OverCompositeOp:
-        case PlusCompositeOp:
-        case ReplaceCompositeOp:
+        case OverlayCompositeOp:
+        case PegtopLightCompositeOp:
+        case PinLightCompositeOp:
         case ScreenCompositeOp:
-        case SrcAtopCompositeOp:
-        case SrcCompositeOp:
+        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:
         {
-          composite_channels=MagickTrue;
+          alpha=Sa+Da-2.0*Sa*Da;
           break;
         }
         default:
+        {
+          alpha=1.0;
           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)
+      if (GetPixelMask(image,p) != 0)
         {
-          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;
-          }
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(image);
+          continue;
         }
-        for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      switch (compose)
+      {
+        case ColorizeCompositeOp:
+        case HueCompositeOp:
+        case LuminizeCompositeOp:
+        case ModulateCompositeOp:
+        case SaturateCompositeOp:
         {
-          MagickRealType
-            pixel;
+          GetPixelInfoPixel(composite_image,p,&source_pixel);
+          GetPixelInfoPixel(image,q,&destination_pixel);
+          break;
+        }
+        default:
+          break;
+      }
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        double
+          sans;
 
-          PixelChannel
-            channel;
+        double
+          pixel;
 
-          PixelTrait
-            composite_traits,
-            traits;
+        PixelChannel
+          channel;
 
-          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:
-            {
-              pixel=gamma*((Sa*Sc)+(Da*Dc)-(Sa*Sc)*(Da*Dc));
-              break;
-            }
-            case XorCompositeOp:
-            {
-              pixel=gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
-              break;
-            }
-            default:
-              break;
-          }
-          q[i]=ClampToQuantum(pixel);
-        }
-      } 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);
+        PixelTrait
+          composite_traits,
+          traits;
+
+        channel=GetPixelChannelChannel(image,i);
+        traits=GetPixelChannelTraits(image,channel);
+        composite_traits=GetPixelChannelTraits(composite_image,channel);
+        if (traits == UndefinedPixelTrait)
+          continue;
+        if ((compose != IntensityCompositeOp) &&
+            (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=(double) GetPixelChannel(composite_image,channel,p);
+        Dc=(double) 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 AlphaCompositeOp:
               {
-                composite.alpha=destination_dissolve*(composite.alpha);
+                pixel=QuantumRange*Sa;
+                break;
+              }
+              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:
+              {
+                MagickBooleanType
+                  equivalent;
+
+                if (Da > ((double) QuantumRange/2.0))
+                  {
+                    pixel=(double) TransparentAlpha;
+                    break;
+                  }
+                equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
+                if (equivalent != MagickFalse)
+                  {
+                    pixel=(double) TransparentAlpha;
+                    break;
+                  }
+                pixel=(double) OpaqueAlpha;
                 break;
               }
               case ClearCompositeOp:
-              case SrcCompositeOp:
               {
-                CompositeClear(&destination,&composite);
+                pixel=(double) 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 CopyAlphaCompositeOp:
+              {
+                pixel=QuantumRange*Sa;
+                if (composite_image->alpha_trait != BlendPixelTrait)
+                  pixel=GetPixelIntensity(composite_image,p);
+                break;
+              }
+              case CopyCompositeOp:
+              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 IntensityCompositeOp:
               {
-                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=GetPixelIntensity(composite_image,p);
+                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);
+              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:
+              {
+                pixel=QuantumRange*alpha;
+                break;
+              }
+            }
+            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=MagickEpsilonReciprocal(alpha);
+        pixel=Dc;
+        switch (compose)
+        {
+          case AlphaCompositeOp:
           {
-            composite=source;
+            pixel=QuantumRange*Sa;
             break;
           }
-          case NoCompositeOp:
-          case DstCompositeOp:
+          case AtopCompositeOp:
+          case SrcAtopCompositeOp:
+          {
+            pixel=Sc*Sa+Dc*(1.0-Sa);
             break;
-          case OverCompositeOp:
-          case SrcOverCompositeOp:
+          }
+          case BlendCompositeOp:
           {
-            CompositePixelInfoOver(&source,source.alpha,&destination,
-              destination.alpha,&composite);
+            pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
             break;
           }
-          case DstOverCompositeOp:
+          case BlurCompositeOp:
+          case DisplaceCompositeOp:
+          case DistortCompositeOp:
+          case CopyCompositeOp:
+          case ReplaceCompositeOp:
+          case SrcCompositeOp:
           {
-            CompositePixelInfoOver(&destination,destination.alpha,&source,
-              source.alpha,&composite);
+            pixel=Sc;
             break;
           }
-          case SrcInCompositeOp:
-          case InCompositeOp:
+          case BumpmapCompositeOp:
+          {
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
+            break;
+          }
+          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;
+              }
+            CompositeHCL(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&sans,&sans,&luma);
+            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &hue,&chroma,&sans);
+            HCLComposite(hue,chroma,luma,&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:
+          case IntensityCompositeOp:
           {
-            CompositeAtop(&destination,&source,&composite);
+            pixel=Dc;
             break;
           }
-          case XorCompositeOp:
+          case CopyBlackCompositeOp:
           {
-            CompositeXor(&source,&destination,&composite);
+            if (channel == BlackPixelChannel)
+              pixel=(double) GetPixelBlack(composite_image,p);
             break;
           }
-          case PlusCompositeOp:
+          case CopyBlueCompositeOp:
+          case CopyYellowCompositeOp:
           {
-            CompositePlus(image,&source,&destination,&composite);
+            if (channel == BluePixelChannel)
+              pixel=(double) GetPixelBlue(composite_image,p);
             break;
           }
-          case MinusDstCompositeOp:
+          case CopyGreenCompositeOp:
+          case CopyMagentaCompositeOp:
           {
-            CompositeMinus(image,&source,&destination,&composite);
+            if (channel == GreenPixelChannel)
+              pixel=(double) GetPixelGreen(composite_image,p);
             break;
           }
-          case MinusSrcCompositeOp:
+          case CopyRedCompositeOp:
+          case CopyCyanCompositeOp:
           {
-            CompositeMinus(image,&destination,&source,&composite);
+            if (channel == RedPixelChannel)
+              pixel=(double) 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;
+              }
+            CompositeHCL(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&chroma,&luma);
+            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &hue,&sans,&sans);
+            HCLComposite(hue,chroma,luma,&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=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+                break;
+              }
+            pixel=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;
+              }
+            CompositeHCL(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&chroma,&luma);
+            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &sans,&sans,&luma);
+            HCLComposite(hue,chroma,luma,&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;
+              }
+            CompositeHCL(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&chroma,&luma);
+            luma+=(0.01*percent_luma*offset)/midpoint;
+            chroma*=0.01*percent_chroma;
+            HCLComposite(hue,chroma,luma,&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=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;
+            CompositeHCL(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&chroma,&luma);
+            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &sans,&chroma,&sans);
+            HCLComposite(hue,chroma,luma,&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;
+            double
+              delta;
+
+            delta=Sc-Dc;
+            if ((double) 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);
     }
@@ -3232,7 +2322,7 @@ MagickBooleanType composite_channels;
           proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_CompositeImage)
+        #pragma omp critical (MagickCore_CompositeImage)
 #endif
         proceed=SetImageProgress(image,CompositeImageTag,progress++,
           image->rows);
@@ -3244,6 +2334,10 @@ MagickBooleanType composite_channels;
   image_view=DestroyCacheView(image_view);
   if (destination_image != (Image * ) NULL)
     destination_image=DestroyImage(destination_image);
+  else
+    composite_image=DestroyImage(composite_image);
+  if (status != MagickFalse)
+    (void) ClampImage(image,exception);
   return(status);
 }
 \f
@@ -3270,7 +2364,7 @@ MagickBooleanType composite_channels;
 %
 %    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,
@@ -3282,6 +2376,9 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
     *image_view,
     *texture_view;
 
+  Image
+    *texture_image;
+
   MagickBooleanType
     status;
 
@@ -3294,34 +2391,41 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
   assert(image->signature == MagickSignature);
   if (texture == (const Image *) NULL)
     return(MagickFalse);
-  (void) SetImageVirtualPixelMethod(texture,TileVirtualPixelMethod);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
+  if (texture_image == (const Image *) NULL)
+    return(MagickFalse);
+  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
+  (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
+    exception);
   status=MagickTrue;
   if ((image->compose != CopyCompositeOp) &&
-      ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
-       (texture->matte != MagickFalse)))
+      ((image->compose != OverCompositeOp) || (image->alpha_trait == BlendPixelTrait) ||
+       (texture_image->alpha_trait == BlendPixelTrait)))
     {
       /*
         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) shared(status) \
+        dynamic_number_threads(image,image->columns,image->rows,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,texture_image,image->compose,
+            MagickFalse,x+texture_image->tile_offset.x,y+
+            texture_image->tile_offset.y,exception);
           if (thread_status == MagickFalse)
             {
               status=thread_status;
@@ -3334,7 +2438,7 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
               proceed;
 
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_TextureImage)
+           #pragma omp critical (MagickCore_TextureImage)
 #endif
             proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
               y,image->rows);
@@ -3344,16 +2448,18 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
       }
       (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
         image->rows,image->rows);
+      texture_image=DestroyImage(texture_image);
       return(status);
     }
   /*
     Tile texture onto the image background (optimized).
   */
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
-  texture_view=AcquireCacheView(texture);
+  texture_view=AcquireVirtualCacheView(texture_image,exception);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+  #pragma omp parallel for schedule(static) shared(status) \
+    dynamic_number_threads(image,image->columns,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3375,34 +2481,53 @@ 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;
+
+        if (GetPixelMask(image,p) != 0)
+          {
+            p+=GetPixelChannels(texture_image);
+            q+=GetPixelChannels(image);
+            continue;
+          }
+        for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
+        {
+          PixelChannel
+            channel;
+
+          PixelTrait
+            texture_traits,
+            traits;
+
+          channel=GetPixelChannelChannel(texture_image,i);
+          texture_traits=GetPixelChannelTraits(texture_image,channel);
+          traits=GetPixelChannelTraits(image,channel);
+          if ((traits == UndefinedPixelTrait) ||
+              (texture_traits == UndefinedPixelTrait))
+            continue;
+          SetPixelChannel(image,channel,p[i],q);
+        }
+        p+=GetPixelChannels(texture_image);
         q+=GetPixelChannels(image);
       }
     }
@@ -3425,5 +2550,6 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
   }
   texture_view=DestroyCacheView(texture_view);
   image_view=DestroyCacheView(image_view);
+  texture_image=DestroyImage(texture_image);
   return(status);
 }