]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/composite.c
(no commit message)
[imagemagick] / MagickCore / composite.c
index 7e3acc531c150caa4c6c8b1f46663b913d258ebd..f0e46aad6cc8a24f2d0adec70a77b8186620bcdf 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -72,6 +72,7 @@
 #include "MagickCore/resource_.h"
 #include "MagickCore/string_.h"
 #include "MagickCore/thread-private.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
        performed as 'pure' mathematical operations, rather than as image
        operations.
 */
-
-static inline MagickRealType Atop(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q,
-  const MagickRealType magick_unused(Da))
-{
-  return(p*Sa+q*(1.0-Sa));  /* Da optimized out,  Da/gamma => 1.0 */
-}
-
-static inline void CompositeAtop(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  composite->alpha=q->alpha;   /* optimized  Da = 1.0-Gamma */
-  composite->red=Atop(p->red,Sa,q->red,1.0);
-  composite->green=Atop(p->green,Sa,q->green,1.0);
-  composite->blue=Atop(p->blue,Sa,q->blue,1.0);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=Atop(p->black,Sa,q->black,1.0);
-}
-
-/*
-  Bumpmap: Multiply by overlay intensity
-  What is this Composition actually method for? Can't find any specification!
-
-  I think this was meant to be a 'HardLight effect' using a Shaded Image!
-  That is a Embossing, using a height map!  Better to do it piecemeal.
-*/
-static inline void CompositeBumpmap(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    intensity;
-
-  intensity=(MagickRealType) GetPixelInfoIntensity(p);
-  composite->red=QuantumScale*intensity*q->red;
-  composite->green=QuantumScale*intensity*q->green;
-  composite->blue=QuantumScale*intensity*q->blue;
-  composite->alpha=(MagickRealType) QuantumScale*intensity*p->alpha;
-  if (q->colorspace == CMYKColorspace)
-    composite->black=QuantumScale*intensity*q->black;
-}
-
-static inline void CompositeClear(const PixelInfo *q,PixelInfo *composite)
-{
-  composite->alpha=(MagickRealType) TransparentAlpha;
-  composite->red=0.0;
-  composite->green=0.0;
-  composite->blue=0.0;
-  composite->black=1.0;
-}
-
-static MagickRealType ColorBurn(const MagickRealType Sca,
-  const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
-{
-  if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
-    return(Sa*Da+Dca*(1.0-Sa));
-  if (Sca < MagickEpsilon)
-    return(Dca*(1.0-Sa));
-  return(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeColorBurn(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*ColorBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*ColorBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*ColorBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*ColorBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-
-static MagickRealType ColorDodge(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    Working from first principles using the original formula:
-
-       f(Sc,Dc) = Dc/(1-Sc)
-
-    This works correctly!  Looks like the 2004 SVG model was right but just
-    required a extra condition for correct handling.
-  */
-  if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
-    return(Sca*(1.0-Da)+Dca*(1.0-Sa));
-  if (fabs(Sca-Sa) < MagickEpsilon)
-    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  return(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeColorDodge(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*ColorDodge(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*ColorDodge(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*ColorDodge(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*ColorDodge(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static inline MagickRealType Darken(const MagickRealType p,
-  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
-{
-  if (p < q)
-    return(MagickOver_(p,alpha,q,beta));  /* src-over */
-  return(MagickOver_(q,beta,p,alpha));    /* dst-over */
-}
-
-static inline void CompositeDarken(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    gamma;
-
-  /*
-    Darken is equivalent to a 'Minimum' method OR a greyscale version of a
-    binary 'Or' OR the 'Intersection' of pixel sets.
-  */
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=MagickMin(p->red,q->red);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=MagickMin(p->green,q->green);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=MagickMin(p->blue,q->blue);
-      if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0 &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=MagickMin(p->black,q->black);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=MagickMax(p->alpha,q->alpha);
-      return;
-    }
-  composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
-  gamma=1.0-QuantumScale*composite->alpha;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Darken(p->red,p->alpha,q->red,q->alpha);
-  composite->green=gamma*Darken(p->green,p->alpha,q->green,q->alpha);
-  composite->blue=gamma*Darken(p->blue,p->alpha,q->blue,q->alpha);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Darken(p->black,p->alpha,q->black,q->alpha);
-}
-
-static inline void CompositeDarkenIntensity(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    Sa;
-
-  /*
-    Select the pixel based on the intensity level.
-    If 'Sync' flag select whole pixel based on alpha weighted intensity.
-    Otherwise use intensity only, but restrict copy according to channel.
-  */
-  if (image->channel_mask != DefaultChannels)
-    {
-      MagickBooleanType
-        from_p;
-
-      from_p=GetPixelInfoIntensity(p) < GetPixelInfoIntensity(q) ? MagickTrue :
-        MagickFalse;
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=from_p != MagickFalse ? p->red : q->red;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=from_p != MagickFalse ? p->green : q->green;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=from_p != MagickFalse ? p->blue : q->blue;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=from_p != MagickFalse ? p->black : q->black;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
-      return;
-    }
-  Sa=QuantumScale*p->alpha;
-  Da=QuantumScale*q->alpha;
-  *composite=(Sa*GetPixelInfoIntensity(p) < Da*GetPixelInfoIntensity(q)) ?
-    *p : *q;
-}
-
-static inline MagickRealType Difference(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q,const MagickRealType Da)
-{
-  /*
-    Optimized by Multipling by QuantumRange (taken from gamma).
-  */
-  return(Sa*p+Da*q-Sa*Da*2.0*MagickMin(p,q));
-}
-
-static inline void CompositeDifference(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=fabs((double) (p->red-q->red));
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=fabs((double) (p->green-q->green));
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=fabs((double) (p->blue-q->blue));
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=fabs((double) (p->black-q->black));
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=fabs((double) (p->alpha-q->alpha));
-     return;
-   }
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Difference(p->red,Sa,q->red,Da);
-  composite->green=gamma*Difference(p->green,Sa,q->green,Da);
-  composite->blue=gamma*Difference(p->blue,Sa,q->blue,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Difference(p->black,Sa,q->black,Da);
-}
-
-static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
-  const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    Divide Source by Destination
-
-      f(Sc,Dc) = Sc / Dc
-
-    But with appropriate handling for special case of Dc == 0 specifically
-    so that   f(Black,Black)=Black  and  f(non-Black,Black)=White.
-    It is however also important to correctly do 'over' alpha blending which
-    is why the formula becomes so complex.
-  */
-  if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
-    return(Sca*(1.0-Da)+Dca*(1.0-Sa));
-  if (fabs(Dca) < MagickEpsilon)
-    return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  return(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeDivide(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=QuantumRange*Divide(QuantumScale*p->red,1.0,
-          QuantumScale*q->red,1.0);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=QuantumRange*Divide(QuantumScale*p->green,1.0,
-          QuantumScale*q->green,1.0);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=QuantumRange*Divide(QuantumScale*p->blue,1.0,
-          QuantumScale*q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Divide(QuantumScale*p->black,1.0,
-          QuantumScale*q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-Divide(Sa,1.0,Da,1.0));
-      return;
-    }
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Divide(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*Divide(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*Divide(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Divide(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static MagickRealType Exclusion(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  return(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeExclusion(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    gamma,
-    Sa,
-    Da;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=QuantumRange*Exclusion(QuantumScale*p->red,1.0,
-          QuantumScale*q->red,1.0);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=QuantumRange*Exclusion(QuantumScale*p->green,1.0,
-          QuantumScale*q->green,1.0);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=QuantumRange*Exclusion(QuantumScale*p->blue,1.0,
-          QuantumScale*q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Exclusion(QuantumScale*p->black,1.0,
-          QuantumScale*q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-Exclusion(Sa,1.0,Da,1.0));
-      return;
-    }
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Exclusion(QuantumScale*p->black*Sa,Sa,
-      QuantumScale*q->black*Da,Da);
-}
-
-static MagickRealType HardLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  if ((2.0*Sca) < Sa)
-    return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-  return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeHardLight(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*HardLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static void CompositeHSB(const MagickRealType red,const MagickRealType green,
-  const MagickRealType blue,double *hue,double *saturation,double *brightness)
+static void CompositeHSB(const double red,const double green,
+  const double blue,double *hue,double *saturation,double *brightness)
 {
-  MagickRealType
+  double
     delta,
     max,
     min;
@@ -629,944 +198,343 @@ static void CompositeHSB(const MagickRealType red,const MagickRealType green,
   *hue=0.0;
   *saturation=0.0;
   *brightness=(double) (QuantumScale*max);
-  if (fabs(max) < MagickEpsilon)
+  if (fabs((double) max) < MagickEpsilon)
     return;
   *saturation=(double) (1.0-min/max);
-  delta=max-min;
+  delta=(MagickRealType) max-min;
   if (fabs(delta) < MagickEpsilon)
     return;
-  if (fabs(red-max) < MagickEpsilon)
+  if (fabs((double) red-max) < MagickEpsilon)
     *hue=(double) ((green-blue)/delta);
   else
-    if (fabs(green-max) < MagickEpsilon)
+    if (fabs((double) green-max) < MagickEpsilon)
       *hue=(double) (2.0+(blue-red)/delta);
     else
-      if (fabs(blue-max) < MagickEpsilon)
+      if (fabs((double) blue-max) < MagickEpsilon)
         *hue=(double) (4.0+(red-green)/delta);
   *hue/=6.0;
   if (*hue < 0.0)
     *hue+=1.0;
 }
 
-#if 0
-static inline MagickRealType In(const MagickRealType p,const MagickRealType Sa,
-  const MagickRealType magick_unused(q),const MagickRealType Da)
-{
-  return(Sa*p*Da);
-}
-#endif
-
-static inline void CompositeIn(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-#if 0
-  MagickRealType
-    gamma,
-    Sa,
-    Da;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=Sa*Da;
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  /* really this just preserves the src or p color as is! */
-  composite->red=gamma*In(p->red,Sa,q->red,Da);
-  composite->green=gamma*In(p->green,Sa,q->green,Da);
-  composite->blue=gamma*In(p->blue,Sa,q->blue,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*In(p->black,Sa,q->black,Da);
-#else
-  /* Simplified to a multiply of the Alpha Channel */
-  *composite=*p; /* structure copy */
-  composite->alpha=QuantumScale*p->alpha*q->alpha;
-#endif
-}
-
-static inline MagickRealType Lighten(const MagickRealType p,
-  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
-{
-   if (p > q)
-     return(MagickOver_(p,alpha,q,beta));  /* src-over */
-   return(MagickOver_(q,beta,p,alpha));    /* dst-over */
-}
-
-static inline void CompositeLighten(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
+static void HSBComposite(const double hue,const double saturation,
+  const double brightness,double *red,double *green,double *blue)
 {
-  MagickRealType
-    gamma;
+  double
+    f,
+    h,
+    p,
+    q,
+    t;
 
   /*
-    Lighten is also equvalent to a 'Maximum' method OR a greyscale version of a
-    binary 'And' OR the 'Union' of pixel sets.
+    Convert HSB to RGB colorspace.
   */
-  if (image->channel_mask != DefaultChannels)
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  if (saturation == 0.0)
     {
-      /*
-        Handle channels as separate grayscale channels
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=MagickMax(p->red,q->red);
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=MagickMax(p->green,q->green);
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=MagickMax(p->blue,q->blue);
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=MagickMax(p->black,q->black);
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=MagickMin(p->alpha,q->alpha);
+      *red=(double) QuantumRange*brightness;
+      *green=(*red);
+      *blue=(*red);
       return;
     }
-  composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
-  gamma=1.0-QuantumScale*composite->alpha;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Lighten(p->red,p->alpha,q->red,q->alpha);
-  composite->green=gamma*Lighten(p->green,p->alpha,q->green,q->alpha);
-  composite->blue=gamma*Lighten(p->blue,p->alpha,q->blue,q->alpha);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Lighten(p->black,p->alpha,q->black,q->alpha);
-}
-
-static inline void CompositeLightenIntensity(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    Sa;
-
-  /*
-    Select the pixel based on the intensity level.
-    If 'Sync' flag select whole pixel based on alpha weighted intensity.
-    Otherwise use Intenisty only, but restrict copy according to channel.
-  */
-  if (image->channel_mask != DefaultChannels)
+  h=6.0*(hue-floor(hue));
+  f=h-floor((double) h);
+  p=brightness*(1.0-saturation);
+  q=brightness*(1.0-saturation*f);
+  t=brightness*(1.0-saturation*(1.0-f));
+  switch ((int) h)
+  {
+    case 0:
+    default:
     {
-      MagickBooleanType
-        from_p;
-
-      from_p=GetPixelInfoIntensity(p) > GetPixelInfoIntensity(q) ? MagickTrue :
-        MagickFalse;
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=from_p != MagickFalse ? p->red : q->red;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=from_p != MagickFalse ? p->green : q->green;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=from_p != MagickFalse ? p->blue : q->blue;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=from_p != MagickFalse ? p->black : q->black;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
-      return;
+      *red=(double) QuantumRange*brightness;
+      *green=(double) QuantumRange*t;
+      *blue=(double) QuantumRange*p;
+      break;
+    }
+    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;
     }
-  Sa=QuantumScale*p->alpha;
-  Da=QuantumScale*q->alpha;
-  *composite=(Sa*GetPixelInfoIntensity(p) > Da*GetPixelInfoIntensity(q)) ?
-    *p : *q;
+    case 5:
+    {
+      *red=(double) QuantumRange*brightness;
+      *green=(double) QuantumRange*p;
+      *blue=(double) QuantumRange*q;
+      break;
+    }
+  }
 }
 
-static inline void CompositeLinearDodge(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
+static inline double MagickMin(const double x,const double y)
 {
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*(p->red*Sa+q->red*Da);
-  composite->green=gamma*(p->green*Sa+q->green*Da);
-  composite->blue=gamma*(p->blue*Sa+q->blue*Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*(p->black*Sa+q->black*Da);
+  if (x < y)
+    return(x);
+  return(y);
 }
 
-
-static inline MagickRealType LinearBurn(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+static inline double MagickMax(const double x,const double y)
 {
-  /*
-    LinearBurn: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
-
-      f(Sc,Dc) = Sc + Dc - 1
-  */
-  return(Sca+Dca-Sa*Da);
+  if (x > y)
+    return(x);
+  return(y);
 }
 
-static inline void CompositeLinearBurn(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
+static MagickBooleanType CompositeOverImage(Image *image,
+  const Image *composite_image,const 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=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*LinearBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
+#define CompositeImageTag  "Composite/Image"
 
-static inline MagickRealType LinearLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    LinearLight: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
+  CacheView
+    *composite_view,
+    *image_view;
 
-      f(Sc,Dc) = Dc + 2*Sc - 1
-  */
-  return((Sca-Sa)*Da+Sca+Dca);
-}
+  MagickBooleanType
+    status;
 
-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);
-}
+  MagickOffsetType
+    progress;
 
-static inline MagickRealType Mathematics(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
-  const GeometryInfo *geometry_info)
-{
-  MagickRealType
-    gamma;
-
-  /*
-    'Mathematics' a free form user control mathematical composition is defined
-    as...
-
-       f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
-
-    Where the arguments A,B,C,D are (currently) passed to composite as
-    a command separated 'geometry' string in "compose:args" image artifact.
-
-       A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
-
-    Applying the SVG transparency formula (see above), we get...
-
-     Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
-
-     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);
-}
-
-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)
-    {
-      /*
-        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.
-
-    As such the removal of the 'sync' flag, is still a usful convention.
-
-    The CompositePixelInfoPlus() function is defined in
-    "composite-private.h" so it can also be used for Image Blending.
-  */
-  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);
-}
+  ssize_t
+    y;
 
-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
+    Composite image.
   */
-  return(Sca+Dca-2.0*Dca*Sa);
-}
-
-static inline void CompositeMinus(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->channel_mask != DefaultChannels)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=p->red-q->red;
-      if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-        composite->green=p->green-q->green;
-      if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-        composite->blue=p->blue-q->blue;
-      if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=p->black-q->black;
-      if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-(Sa-Da));
-      return;
-    }
-  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Minus(p->red*Sa,Sa,q->red*Da,Da);
-  composite->green=gamma*Minus(p->green*Sa,Sa,q->green*Da,Da);
-  composite->blue=gamma*Minus(p->blue*Sa,Sa,q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Minus(p->black*Sa,Sa,q->black*Da,Da);
-}
-
-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;
+  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)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    const Quantum
+      *pixels;
 
-  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);
-}
+    register const Quantum
+      *restrict p;
 
-static inline MagickRealType ModulusSubtract(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
-{
-  MagickRealType
-    pixel;
+    register Quantum
+      *restrict q;
 
-  pixel=p-q;
-  if (pixel < 0.0)
-    pixel+=(QuantumRange+1.0);
-  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
-}
+    register ssize_t
+      x;
 
-static inline void CompositeModulusSubtract(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
+    size_t
+      channels;
 
-  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=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);
-}
+      MagickRealType
+        alpha,
+        Da,
+        Dc,
+        gamma,
+        Sa,
+        Sc;
 
-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));
-}
+      register ssize_t
+        i;
 
-static inline void CompositeMultiply(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    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];
 
-  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=GetPixelChannelMapChannel(image,i);
+            traits=GetPixelChannelMapTraits(image,channel);
+            composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            q[i]=source[channel];
+          }
+          q+=GetPixelChannels(image);
+          continue;
+        }
       /*
-        Handle channels as separate grayscale channels.
+        Authentic composite:
+          Sa:  normalized source alpha.
+          Da:  normalized destination alpha.
       */
-      if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-        composite->red=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=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (composite_traits == UndefinedPixelTrait))
+          continue;
+        if ((traits & CopyPixelTrait) != 0)
+          {
+            if (channel != AlphaPixelChannel)
+              {
+                /*
+                  Copy channel.
+                */
+                q[i]=GetPixelChannel(composite_image,channel,p);
+                continue;
+              }
+            /*
+              Set alpha channel.
+            */
+            q[i]=ClampToQuantum(QuantumRange*alpha);
+            continue;
+          }
+        /*
+          Sc: source color.
+          Dc: destination color.
+        */
+        Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
+        Dc=(MagickRealType) q[i];
+        gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        q[i]=ClampToQuantum(gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc));
+      }
+      p+=GetPixelChannels(composite_image);
+      channels=GetPixelChannels(composite_image);
+      if (p >= (pixels+channels*composite_image->columns))
+        p=pixels;
+      q+=GetPixelChannels(image);
     }
-  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_image,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,12 +542,6 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     *composite_view,
     *image_view;
 
-  const char
-    *value;
-
-  double
-    sans;
-
   GeometryInfo
     geometry_info;
 
@@ -1587,7 +549,6 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     *destination_image;
 
   MagickBooleanType
-    modify_outside_overlay,
     status;
 
   MagickOffsetType
@@ -1608,9 +569,6 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
   ssize_t
     y;
 
-  /*
-    Prepare composite image.
-  */
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
@@ -1619,31 +577,24 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
   assert(composite_image->signature == MagickSignature);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
+      (IsGrayColorspace(composite_image->colorspace) == MagickFalse))
+    (void) TransformImageColorspace(image,sRGBColorspace,exception);
+  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
+    {
+      status=CompositeOverImage(image,composite_image,clip_to_self,x_offset,
+        y_offset,exception);
+      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;
   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 +604,10 @@ 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)
 #endif
       for (y=0; y < (ssize_t) composite_image->rows; y++)
       {
@@ -1685,12 +636,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(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=GetPixelChannelMapChannel(composite_image,i);
+            composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+            traits=GetPixelChannelMapTraits(image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            SetPixelChannel(image,channel,p[i],q);
+          }
           p+=GetPixelChannels(composite_image);
           q+=GetPixelChannels(image);
         }
@@ -1703,7 +674,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);
@@ -1715,16 +686,19 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       image_view=DestroyCacheView(image_view);
       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)
-        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      modify_outside_overlay=MagickTrue;
+        {
+          (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+          image->matte=MagickFalse;
+        }
       break;
     }
     case BlurCompositeOp:
@@ -1733,6 +707,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         *composite_view,
         *destination_view;
 
+      const char
+        *value;
+
       PixelInfo
         pixel;
 
@@ -1749,6 +726,8 @@ 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]].
       */
@@ -1757,28 +736,35 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       if (destination_image == (Image *) NULL)
         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);
           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
@@ -1790,18 +776,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
@@ -1843,13 +843,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);
@@ -1872,6 +879,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         *destination_view,
         *image_view;
 
+      const char
+        *value;
+
       PixelInfo
         pixel;
 
@@ -1970,9 +980,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
@@ -2020,8 +1030,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
             Mask with the 'invalid pixel mask' in alpha channel.
           */
           pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
-            pixel.alpha)*(1.0-QuantumScale*
-            GetPixelAlpha(composite_image,p)));
+            pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
           SetPixelInfoPixel(destination_image,&pixel,q);
           p+=GetPixelChannels(composite_image);
           q+=GetPixelChannels(destination_image);
@@ -2038,6 +1047,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case DissolveCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Geometry arguments to dissolve factors.
       */
@@ -2058,17 +1070,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 +1094,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,6 +1118,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case ModulateCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Determine the brightness and saturation scale.
       */
@@ -2116,6 +1136,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case ThresholdCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Determine the amount and threshold.
       */
@@ -2134,19 +1157,16 @@ 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);
+  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)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2154,10 +1174,17 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       *pixels;
 
     double
+      blue,
       brightness,
+      green,
       hue,
+      red,
       saturation;
 
+    PixelInfo
+      destination_pixel,
+      source_pixel;
+
     register const Quantum
       *restrict p;
 
@@ -2167,11 +1194,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;
@@ -2205,9 +1230,27 @@ MagickBooleanType composite_channels;
     hue=0.0;
     saturation=0.0;
     brightness=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)
+      MagickRealType
+        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,794 +1260,1018 @@ 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++)
+          {
+            MagickRealType
+              pixel;
+
+            PixelChannel
+              channel;
+
+            PixelTrait
+              composite_traits,
+              traits;
+
+            channel=GetPixelChannelMapChannel(image,i);
+            traits=GetPixelChannelMapTraits(image,channel);
+            composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (composite_traits == UndefinedPixelTrait))
+              continue;
+            switch (compose)
+            {
+              case AlphaCompositeOp:
+              case ChangeMaskCompositeOp:
+              case CopyAlphaCompositeOp:
+              case DstAtopCompositeOp:
+              case DstInCompositeOp:
+              case InCompositeOp:
+              case IntensityCompositeOp:
+              case OutCompositeOp:
+              case SrcInCompositeOp:
+              case SrcOutCompositeOp:
+              {
+                pixel=(MagickRealType) q[i];
+                if (channel == AlphaPixelChannel)
+                  pixel=(MagickRealType) TransparentAlpha;
+                break;
+              }
+              case ClearCompositeOp:
+              case CopyCompositeOp:
+              case ReplaceCompositeOp:
+              case SrcCompositeOp:
+              {
+                if (channel == AlphaPixelChannel)
+                  {
+                    pixel=(MagickRealType) TransparentAlpha;
+                    break;
+                  }
+                pixel=0.0;
+                break;
+              }
+              case BlendCompositeOp:
+              case DissolveCompositeOp:
+              {
+                if (channel == AlphaPixelChannel)
+                  {
+                    pixel=destination_dissolve*GetPixelAlpha(composite_image,
+                      source);
+                    break;
+                  }
+                pixel=(MagickRealType) source[channel];
+                break;
+              }
+              default:
+              {
+                pixel=(MagickRealType) source[channel];
+                break;
+              }
+            }
+            q[i]=ClampToQuantum(pixel);
+          }
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      /*
+        Authentic composite:
+          Sa:  normalized source alpha.
+          Da:  normalized destination alpha.
+      */
+      Sa=QuantumScale*GetPixelAlpha(composite_image,p);
+      Da=QuantumScale*GetPixelAlpha(image,q);
+      switch (compose)
+      {
+        case BumpmapCompositeOp:
+        {
+          alpha=GetPixelIntensity(composite_image,p)*Sa;
+          break;
+        }
+        case ColorBurnCompositeOp:
+        case ColorDodgeCompositeOp:
+        case DifferenceCompositeOp:
+        case DivideDstCompositeOp:
+        case DivideSrcCompositeOp:
+        case ExclusionCompositeOp:
+        case HardLightCompositeOp:
+        case LinearBurnCompositeOp:
+        case LinearDodgeCompositeOp:
+        case LinearLightCompositeOp:
+        case MathematicsCompositeOp:
+        case MinusDstCompositeOp:
+        case MinusSrcCompositeOp:
+        case ModulusAddCompositeOp:
+        case ModulusSubtractCompositeOp:
+        case MultiplyCompositeOp:
+        case OverlayCompositeOp:
+        case PegtopLightCompositeOp:
+        case PinLightCompositeOp:
+        case ScreenCompositeOp:
+        case SoftLightCompositeOp:
+        case VividLightCompositeOp:
+        {
+          alpha=RoundToUnity(Sa+Da-Sa*Da);
+          break;
+        }
+        case DarkenCompositeOp:
+        case DstAtopCompositeOp:
+        case DstInCompositeOp:
+        case InCompositeOp:
+        case LightenCompositeOp:
+        case SrcInCompositeOp:
+        {
+          alpha=Sa*Da;
+          break;
+        }
+        case DissolveCompositeOp:
+        {
+          alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
+            Sa+destination_dissolve*Da;
+          break;
+        }
+        case DstOverCompositeOp:
+        {
+          alpha=Da*(-Sa)+Da+Sa;
+          break;
+        }
+        case DstOutCompositeOp:
+        {
+          alpha=Da*(1.0-Sa);
+          break;
+        }
+        case OutCompositeOp:
+        case SrcOutCompositeOp:
+        {
+          alpha=Sa*(1.0-Da);
+          break;
+        }
+        case OverCompositeOp:
+        case SrcOverCompositeOp:
+        {
+          alpha=Sa*(-Da)+Sa+Da;
+          break;
+        }
+        case BlendCompositeOp:
+        case PlusCompositeOp:
+        {
+          alpha=RoundToUnity(Sa+Da);
+          break;
+        }
+        case XorCompositeOp:
+        {
+          alpha=Sa+Da-2.0*Sa*Da;
+          break;
+        }
+        default:
+        {
+          alpha=1.0;
+          break;
+        }
+      }
+      if (GetPixelMask(image,p) != 0)
+        {
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(image);
+          continue;
+        }
       switch (compose)
       {
-        case AtopCompositeOp:
-        case ClearCompositeOp:
-        case CopyCompositeOp:
-        case DstAtopCompositeOp:
-        case DstCompositeOp:
-        case DstInCompositeOp:
-        case DstOverCompositeOp:
-        case DstOutCompositeOp:
-        case InCompositeOp:
-        case OutCompositeOp:
-        case OverCompositeOp:
-        case ReplaceCompositeOp:
-        case SrcAtopCompositeOp:
-        case SrcCompositeOp:
-        case SrcInCompositeOp:
-        case SrcOutCompositeOp:
-        case SrcOverCompositeOp:
-        case XorCompositeOp:
+        case ColorizeCompositeOp:
+        case HueCompositeOp:
+        case LuminizeCompositeOp:
+        case ModulateCompositeOp:
+        case SaturateCompositeOp:
         {
-          composite_channels=MagickTrue;
+          GetPixelInfoPixel(composite_image,p,&source_pixel);
+          GetPixelInfoPixel(image,q,&destination_pixel);
           break;
         }
         default:
           break;
       }
-      if (composite_channels != MagickFalse) {
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        double
+          sans;
+
         MagickRealType
-          Da,
-          Dc,
-          gamma,
-          Sa,
-          Sc;
+          pixel;
 
-        register ssize_t
-          i;
+        PixelChannel
+          channel;
 
-        if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
-            ((x-x_offset) >= (ssize_t) composite_image->columns))
-          {
-            Quantum
-              source[MaxPixelChannels];
+        PixelTrait
+          composite_traits,
+          traits;
 
+        channel=GetPixelChannelMapChannel(image,i);
+        traits=GetPixelChannelMapTraits(image,channel);
+        composite_traits=GetPixelChannelMapTraits(composite_image,channel);
+        if (traits == UndefinedPixelTrait)
+          continue;
+        if ((compose != IntensityCompositeOp) &&
+            (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]=ClampToQuantum(Sc);
+                continue;
+              }
             /*
-              Virtual composite:
-                Sc: source color.
-                Dc: destination color.
+              Set alpha channel.
             */
-            (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
-              source,exception);
-            for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+            switch (compose)
             {
-              MagickRealType
-                pixel;
-
-              PixelChannel
-                channel;
-
-              PixelTrait
-                traits;
-
-              channel=GetPixelChannelMapChannel(image,i);
-              traits=GetPixelChannelMapTraits(image,channel);
-              if (traits == UndefinedPixelTrait)
-                continue;
-              switch (compose)
+              case AlphaCompositeOp:
               {
-                case ClearCompositeOp:
-                case CopyCompositeOp:
-                case ReplaceCompositeOp:
-                case SrcCompositeOp:
-                {
-                  pixel=0.0;
-                  if (channel == AlphaPixelChannel)
+                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 > ((MagickRealType) QuantumRange/2.0))
+                  {
                     pixel=(MagickRealType) TransparentAlpha;
-                  break;
-                }
-                case DstAtopCompositeOp:
-                case InCompositeOp:
-                case OutCompositeOp:
-                case SrcInCompositeOp:
-                case SrcOutCompositeOp:
-                {
-                  pixel=(MagickRealType) q[i];
-                  if (channel == AlphaPixelChannel)
+                    break;
+                  }
+                equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
+                if (equivalent != MagickFalse)
+                  {
                     pixel=(MagickRealType) TransparentAlpha;
-                  break;
-                }
-                default:
-                {
-                  pixel=source[channel];
-                  break;
-                }
+                    break;
+                  }
+                pixel=(MagickRealType) OpaqueAlpha;
+                break;
               }
-              q[i]=ClampToQuantum(pixel);
-            }
-            q+=GetPixelChannels(image);
-            continue;
-          }
-        /*
-          Authentic composite:
-            Sa: source normalized alpha.
-            Da: destination normalized alpha.
-        */
-        Sa=QuantumScale*GetPixelAlpha(composite_image,p);
-        Da=QuantumScale*GetPixelAlpha(image,q);
-        switch (compose)
-        {
-          case DstOverCompositeOp:
-          {
-            gamma=Da*(-Sa)+Da+Sa;
-            break;
-          }
-          case DstAtopCompositeOp:
-          case DstInCompositeOp:
-          case InCompositeOp:
-          case SrcInCompositeOp:
-          {
-            gamma=Sa*Da;
-            break;
-          }
-          case DstOutCompositeOp:
-          {
-            gamma=Da*(1.0-Sa);
-            break;
-          }
-          case OutCompositeOp:
-          case SrcOutCompositeOp:
-          {
-            gamma=Sa*(1.0-Da);
-            break;
-          }
-          case OverCompositeOp:
-          case SrcOverCompositeOp:
-          {
-            gamma=Sa*(-Da)+Sa+Da;
-            break;
-          }
-          case XorCompositeOp:
-          {
-            gamma=Sa+Da-2.0*Sa*Da;
-            break;
-          }
-          default:
-          {
-            gamma=1.0;
-            break;
-          }
-        }
-        for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
-        {
-          MagickRealType
-            pixel;
-
-          PixelChannel
-            channel;
-
-          PixelTrait
-            composite_traits,
-            traits;
-
-          channel=GetPixelChannelMapChannel(image,i);
-          traits=GetPixelChannelMapTraits(image,channel);
-          composite_traits=GetPixelChannelMapTraits(composite_image,channel);
-          if ((traits == UndefinedPixelTrait) ||
-              (composite_traits == UndefinedPixelTrait))
-            continue;
-          /*
-            Sc: source color.
-            Dc: destination color.
-          */
-          Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
-          Dc=(MagickRealType) q[i];
-          if ((traits & CopyPixelTrait) != 0)
-            {
-              if (channel != AlphaPixelChannel)
-                {
-                  /*
-                    Copy channel.
-                  */
-                  q[i]=Sc;
-                  continue;
-                }
-              /*
-                Set alpha channel.
-              */
-              pixel=0.0;
-              switch (compose)
+              case ClearCompositeOp:
               {
-                case CopyCompositeOp:
-                case DstAtopCompositeOp:
-                case ReplaceCompositeOp:
-                case SrcCompositeOp:
-                {
-                  pixel=QuantumRange*Sa;
-                  break;
-                }
-                case AtopCompositeOp:
-                case SrcAtopCompositeOp:
-                case DstCompositeOp:
-                {
-                  pixel=QuantumRange*Da;
-                  break;
-                }
-                default:
-                {
-                  pixel=QuantumRange*gamma;
-                  break;
-                }
+                pixel=(MagickRealType) TransparentAlpha;
+                break;
               }
-              q[i]=ClampToQuantum(pixel);
-              continue;
-            }
-          /*
-            Porter-Duff compositions.
-          */
-          pixel=0.0;
-          switch (compose)
-          {
-            case AtopCompositeOp:
-            case SrcAtopCompositeOp:
-            {
-              pixel=Sc*Sa+Dc*(1.0-Sa);
-              break;
-            }
-            case CopyCompositeOp:
-            case ReplaceCompositeOp:
-            case SrcCompositeOp:
-            {
-              pixel=Sc;
-              break;
-            }
-            case DstAtopCompositeOp:
-            {
-              pixel=Dc*Da+Sc*(1.0-Da);
-              break;
-            }
-            case DstCompositeOp:
-            {
-              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 InCompositeOp:
-            case SrcInCompositeOp:
-            {
-              pixel=gamma*(Da*Sc*Da);
-              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 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);
-        /*
-          Handle destination modifications outside overlaid region.
-        */
-        composite=destination;
-        if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
-            ((x-x_offset) >= (ssize_t) composite_image->columns))
-          {
-            switch (compose)
-            {
-              case DissolveCompositeOp:
-              case BlendCompositeOp:
+              case ColorizeCompositeOp:
+              case HueCompositeOp:
+              case LuminizeCompositeOp:
+              case SaturateCompositeOp:
               {
-                composite.alpha=destination_dissolve*(composite.alpha);
+                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 ClearCompositeOp:
+              case CopyCompositeOp:
+              case CopyAlphaCompositeOp:
+              case DisplaceCompositeOp:
+              case DistortCompositeOp:
+              case DstAtopCompositeOp:
+              case ReplaceCompositeOp:
               case SrcCompositeOp:
               {
-                CompositeClear(&destination,&composite);
+                pixel=QuantumRange*Sa;
                 break;
               }
-              case InCompositeOp:
-              case SrcInCompositeOp:
-              case OutCompositeOp:
-              case SrcOutCompositeOp:
-              case DstInCompositeOp:
-              case DstAtopCompositeOp:
-              case CopyOpacityCompositeOp:
-              case ChangeMaskCompositeOp:
+              case DarkenIntensityCompositeOp:
               {
-                composite.alpha=(MagickRealType) TransparentAlpha;
+                pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
+                  (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
                 break;
               }
-              default:
+              case IntensityCompositeOp:
               {
-                (void) GetOneVirtualPixelInfo(composite_image,
-                  GetPixelCacheVirtualMethod(composite_image),x-x_offset,y-
-                  y_offset,&composite,exception);
+                pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
                 break;
               }
-            }
-            if (image->colorspace == CMYKColorspace)
+              case LightenIntensityCompositeOp:
               {
-                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=Sa*GetPixelIntensity(composite_image,p) >
+                  Da*GetPixelIntensity(image,q) ? Sa : Da;
+                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 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=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : 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:
           {
-            CompositeIn(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
             break;
           }
-          case DstInCompositeOp:
+          case ChangeMaskCompositeOp:
           {
-            CompositeIn(&destination,&source,&composite);
+            pixel=Dc;
             break;
           }
-          case OutCompositeOp:
-          case SrcOutCompositeOp:
+          case ClearCompositeOp:
           {
-            CompositeOut(&source,&destination,&composite);
+            pixel=0.0;
             break;
           }
-          case DstOutCompositeOp:
+          case ColorBurnCompositeOp:
           {
-            CompositeOut(&destination,&source,&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 AtopCompositeOp:
-          case SrcAtopCompositeOp:
+          case ColorDodgeCompositeOp:
+          {
+            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 ColorizeCompositeOp:
           {
-            CompositeAtop(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&sans,&sans,&brightness);
+            CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &hue,&saturation,&sans);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case DstAtopCompositeOp:
+          case CopyAlphaCompositeOp:
+          case IntensityCompositeOp:
           {
-            CompositeAtop(&destination,&source,&composite);
+            if (channel == AlphaPixelChannel)
+              pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
             break;
           }
-          case XorCompositeOp:
+          case CopyBlackCompositeOp:
           {
-            CompositeXor(&source,&destination,&composite);
+            if (channel == BlackPixelChannel)
+              pixel=(MagickRealType) GetPixelBlack(composite_image,p);
             break;
           }
-          case PlusCompositeOp:
+          case CopyBlueCompositeOp:
+          case CopyYellowCompositeOp:
           {
-            CompositePlus(image,&source,&destination,&composite);
+            if (channel == BluePixelChannel)
+              pixel=(MagickRealType) GetPixelBlue(composite_image,p);
             break;
           }
-          case MinusDstCompositeOp:
+          case CopyGreenCompositeOp:
+          case CopyMagentaCompositeOp:
           {
-            CompositeMinus(image,&source,&destination,&composite);
+            if (channel == GreenPixelChannel)
+              pixel=(MagickRealType) GetPixelGreen(composite_image,p);
             break;
           }
-          case MinusSrcCompositeOp:
+          case CopyRedCompositeOp:
+          case CopyCyanCompositeOp:
           {
-            CompositeMinus(image,&destination,&source,&composite);
+            if (channel == RedPixelChannel)
+              pixel=(MagickRealType) GetPixelRed(composite_image,p);
             break;
           }
-          case ModulusAddCompositeOp:
+          case DarkenCompositeOp:
           {
-            CompositeModulusAdd(image,&source,&destination,&composite);
+            /*
+              Darken is equivalent to a 'Minimum' method
+                OR a greyscale version of a binary 'Or'
+                OR the 'Intersection' of pixel sets.
+            */
+            if (Sc < Dc)
+              {
+                pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+                break;
+              }
+            pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
             break;
           }
-          case ModulusSubtractCompositeOp:
+          case DarkenIntensityCompositeOp:
           {
-            CompositeModulusSubtract(image,&source,&destination,&composite);
+            pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
+              (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
             break;
           }
           case DifferenceCompositeOp:
           {
-            CompositeDifference(image,&source,&destination,&composite);
+            pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
             break;
           }
-          case ExclusionCompositeOp:
+          case DissolveCompositeOp:
           {
-            CompositeExclusion(image,&source,&destination,&composite);
+            pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
+              destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
             break;
           }
-          case MultiplyCompositeOp:
+          case DivideDstCompositeOp:
           {
-            CompositeMultiply(image,&source,&destination,&composite);
+            if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if (fabs(Dca) < MagickEpsilon)
+              {
+                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case ScreenCompositeOp:
+          case DivideSrcCompositeOp:
           {
-            CompositeScreen(image,&source,&destination,&composite);
+            if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
+                break;
+              }
+            if (fabs(Sca) < MagickEpsilon)
+              {
+                pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
             break;
           }
-          case DivideDstCompositeOp:
+          case DstAtopCompositeOp:
           {
-            CompositeDivide(image,&source,&destination,&composite);
+            pixel=Dc*Da+Sc*(1.0-Da);
             break;
           }
-          case DivideSrcCompositeOp:
+          case DstCompositeOp:
+          case NoCompositeOp:
           {
-            CompositeDivide(image,&destination,&source,&composite);
+            pixel=Dc;
             break;
           }
-          case DarkenCompositeOp:
+          case DstInCompositeOp:
           {
-            CompositeDarken(image,&source,&destination,&composite);
+            pixel=gamma*(Sa*Dc*Sa);
             break;
           }
-          case LightenCompositeOp:
+          case DstOutCompositeOp:
           {
-            CompositeLighten(image,&source,&destination,&composite);
+            pixel=gamma*(Da*Dc*(1.0-Sa));
             break;
           }
-          case DarkenIntensityCompositeOp:
+          case DstOverCompositeOp:
           {
-            CompositeDarkenIntensity(image,&source,&destination,&composite);
+            pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
             break;
           }
-          case LightenIntensityCompositeOp:
+          case ExclusionCompositeOp:
           {
-            CompositeLightenIntensity(image,&source,&destination,&composite);
+            pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
             break;
           }
-          case MathematicsCompositeOp:
+          case HardLightCompositeOp:
           {
-            CompositeMathematics(image,&source,&destination,&geometry_info,
-              &composite);
+            if ((2.0*Sca) < Sa)
+              {
+                pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
+                  (1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
             break;
           }
-          case ColorDodgeCompositeOp:
+          case HueCompositeOp:
           {
-            CompositeColorDodge(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&saturation,&brightness);
+            CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &hue,&sans,&sans);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case ColorBurnCompositeOp:
+          case InCompositeOp:
+          case SrcInCompositeOp:
           {
-            CompositeColorBurn(&source,&destination,&composite);
+            pixel=gamma*(Da*Sc*Da);
             break;
           }
-          case LinearDodgeCompositeOp:
+          case LinearBurnCompositeOp:
           {
-            CompositeLinearDodge(&source,&destination,&composite);
+            /*
+              LinearBurn: as defined by Abode Photoshop, according to
+              http://www.simplefilter.de/en/basics/mixmods.html is:
+
+                f(Sc,Dc) = Sc + Dc - 1
+            */
+            pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
             break;
           }
-          case LinearBurnCompositeOp:
+          case LinearDodgeCompositeOp:
           {
-            CompositeLinearBurn(&source,&destination,&composite);
+            pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
             break;
           }
-          case HardLightCompositeOp:
+          case LinearLightCompositeOp:
           {
-            CompositeHardLight(&source,&destination,&composite);
+            /*
+              LinearLight: as defined by Abode Photoshop, according to
+              http://www.simplefilter.de/en/basics/mixmods.html is:
+
+                f(Sc,Dc) = Dc + 2*Sc - 1
+            */
+            pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
             break;
           }
-          case OverlayCompositeOp:
+          case LightenCompositeOp:
           {
-            CompositeHardLight(&destination,&source,&composite);
+            if (Sc > Dc)
+              {
+                pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+                break;
+              }
+            pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
             break;
           }
-          case SoftLightCompositeOp:
+          case LightenIntensityCompositeOp:
           {
-            CompositeSoftLight(&source,&destination,&composite);
+            /*
+              Lighten is equivalent to a 'Maximum' method
+                OR a greyscale version of a binary 'And'
+                OR the 'Union' of pixel sets.
+            */
+            pixel=Sa*GetPixelIntensity(composite_image,p) >
+              Da*GetPixelIntensity(image,q) ? Sc : Dc;
             break;
           }
-          case LinearLightCompositeOp:
+          case LuminizeCompositeOp:
           {
-            CompositeLinearLight(&source,&destination,&composite);
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&saturation,&brightness);
+            CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &sans,&sans,&brightness);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case PegtopLightCompositeOp:
+          case MathematicsCompositeOp:
           {
-            CompositePegtopLight(&source,&destination,&composite);
+            /*
+              'Mathematics' a free form user control mathematical composition
+              is defined as...
+
+                f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
+
+              Where the arguments A,B,C,D are (currently) passed to composite
+              as a command separated 'geometry' string in "compose:args" image
+              artifact.
+
+                 A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
+
+              Applying the SVG transparency formula (see above), we get...
+
+               Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
+
+               Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
+                 Dca*(1.0-Sa)
+            */
+            pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
+              Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
+              Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
             break;
           }
-          case VividLightCompositeOp:
+          case MinusDstCompositeOp:
           {
-            CompositeVividLight(&source,&destination,&composite);
+            pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
             break;
           }
-          case PinLightCompositeOp:
+          case MinusSrcCompositeOp:
           {
-            CompositePinLight(&source,&destination,&composite);
+            /*
+              Minus source from destination.
+
+                f(Sc,Dc) = Sc - Dc
+            */
+            pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
             break;
           }
-          case ChangeMaskCompositeOp:
+          case ModulateCompositeOp:
           {
-            if ((composite.alpha > ((MagickRealType) QuantumRange/2.0)) ||
-                (IsFuzzyEquivalencePixelInfo(&source,&destination) != MagickFalse))
-              composite.alpha=(MagickRealType) TransparentAlpha;
-            else
-              composite.alpha=(MagickRealType) OpaqueAlpha;
+            ssize_t
+              offset;
+
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
+            if (offset == 0)
+              {
+                pixel=Dc;
+                break;
+              }
+            CompositeHSB(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&saturation,&brightness);
+            brightness+=(0.01*percent_brightness*offset)/midpoint;
+            saturation*=0.01*percent_saturation;
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case BumpmapCompositeOp:
+          case ModulusAddCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            CompositeBumpmap(&source,&destination,&composite);
+            pixel=Sc+Dc;
+            if (pixel > QuantumRange)
+              pixel-=(QuantumRange+1.0);
+            pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
             break;
           }
-          case DissolveCompositeOp:
+          case ModulusSubtractCompositeOp:
           {
-            CompositePixelInfoOver(&source,source_dissolve*source.alpha,
-              &destination,(MagickRealType) (destination_dissolve*
-              destination.alpha),&composite);
+            pixel=Sc-Dc;
+            if (pixel < 0.0)
+              pixel+=(QuantumRange+1.0);
+            pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
             break;
           }
-          case BlendCompositeOp:
+          case MultiplyCompositeOp:
           {
-            CompositePixelInfoBlend(&source,source_dissolve,&destination,
-              destination_dissolve,&composite);
+            pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case ThresholdCompositeOp:
+          case OutCompositeOp:
+          case SrcOutCompositeOp:
           {
-            CompositeThreshold(&source,&destination,threshold,amount,&composite);
+            pixel=gamma*(Sa*Sc*(1.0-Da));
             break;
           }
-          case ModulateCompositeOp:
+          case OverCompositeOp:
+          case SrcOverCompositeOp:
           {
-            double
-              blue,
-              green,
-              red;
-
-            ssize_t
-              offset;
-
-            if (source.alpha == TransparentAlpha)
-              break;
-            offset=(ssize_t) (GetPixelInfoIntensity(&source)-midpoint);
-            if (offset == 0)
-              break;
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            brightness+=(0.01*percent_brightness*offset)/midpoint;
-            saturation*=0.01*percent_saturation;
-            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
-            composite.red=red;
-            composite.green=green;
-            composite.blue=blue;
+            pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
             break;
           }
-          case HueCompositeOp:
+          case OverlayCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            if ((2.0*Dca) < Da)
               {
-                composite=source;
+                pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
+                  (1.0-Da));
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&hue,&sans,&sans);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
+              Sca*(1.0-Da));
             break;
           }
-          case SaturateCompositeOp:
+          case PegtopLightCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            /*
+              PegTop: A Soft-Light alternative: A continuous version of the
+              Softlight function, producing very similar results.
+
+                f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
+
+              http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
+            */
+            if (fabs(Da) < MagickEpsilon)
               {
-                composite=source;
+                pixel=QuantumRange*gamma*(Sca);
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&sans,&saturation,
-              &sans);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
+              Da)+Dca*(1.0-Sa));
             break;
           }
-          case LuminizeCompositeOp:
+          case PinLightCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            /*
+              PinLight: A Photoshop 7 composition method
+              http://www.simplefilter.de/en/basics/mixmods.html
+
+                f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
+            */
+            if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
+              {
+                pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
+                break;
+              }
+            if ((Dca*Sa) > (2.0*Sca*Da))
               {
-                composite=source;
+                pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
                 break;
               }
-            CompositeHSB(destination.red,destination.green,destination.blue,&hue,
-              &saturation,&brightness);
-            CompositeHSB(source.red,source.green,source.blue,&sans,&sans,
-              &brightness);
-            HSBComposite(hue,saturation,brightness,&composite.red,
-              &composite.green,&composite.blue);
-            if (source.alpha < destination.alpha)
-              composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
             break;
           }
-          case ColorizeCompositeOp:
+          case PlusCompositeOp:
           {
-            if (source.alpha == TransparentAlpha)
-              break;
-            if (destination.alpha == TransparentAlpha)
+            pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
+            break;
+          }
+          case SaturateCompositeOp:
+          {
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
               {
-                composite=source;
+                pixel=Dc;
                 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;
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Sc;
+                break;
+              }
+            CompositeHSB(destination_pixel.red,destination_pixel.green,
+              destination_pixel.blue,&hue,&saturation,&brightness);
+            CompositeHSB(source_pixel.red,source_pixel.green,source_pixel.blue,
+              &sans,&saturation,&sans);
+            HSBComposite(hue,saturation,brightness,&red,&green,&blue);
+            switch (channel)
+            {
+              case RedPixelChannel: pixel=red; break;
+              case GreenPixelChannel: pixel=green; break;
+              case BluePixelChannel: pixel=blue; break;
+              default: pixel=Dc; break;
+            }
             break;
           }
-          case CopyRedCompositeOp:
-          case CopyCyanCompositeOp:
+          case ScreenCompositeOp:
           {
-            composite.red=source.red;
+            /*
+              Screen:  a negated multiply:
+
+                f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
+            */
+            pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
             break;
           }
-          case CopyGreenCompositeOp:
-          case CopyMagentaCompositeOp:
+          case SoftLightCompositeOp:
           {
-            composite.green=source.green;
+            /*
+              Refer to the March 2009 SVG specification.
+            */
+            if ((2.0*Sca) < Sa)
+              {
+                pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
+                  Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
+              {
+                pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
+                  (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
+                  Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
+              (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
             break;
           }
-          case CopyBlueCompositeOp:
-          case CopyYellowCompositeOp:
+          case ThresholdCompositeOp:
           {
-            composite.blue=source.blue;
+            MagickRealType
+              delta;
+
+            delta=Sc-Dc;
+            if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
+              {
+                pixel=gamma*Dc;
+                break;
+              }
+            pixel=gamma*(Dc+delta*amount);
             break;
           }
-          case CopyOpacityCompositeOp:
+          case VividLightCompositeOp:
           {
-            if (source.matte == MagickFalse)
+            /*
+              VividLight: A Photoshop 7 composition method.  See
+              http://www.simplefilter.de/en/basics/mixmods.html.
+
+                f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
+            */
+            if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
+              {
+                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            if ((2.0*Sca) <= Sa)
               {
-                composite.alpha=(MagickRealType) GetPixelInfoIntensity(&source);
+                pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
+                  (1.0-Da)+Dca*(1.0-Sa));
                 break;
               }
-            composite.alpha=source.alpha;
+            pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
             break;
           }
-          case CopyBlackCompositeOp:
+          case XorCompositeOp:
           {
-            if (source.colorspace != CMYKColorspace)
-              ConvertRGBToCMYK(&source);
-            composite.black=source.black;
+            pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
             break;
           }
-          case BlurCompositeOp:
-          case DisplaceCompositeOp:
-          case DistortCompositeOp:
+          default:
           {
-            composite=source;
+            pixel=Sc;
             break;
           }
-          default:
-            break;
         }
-        if (image->colorspace == CMYKColorspace)
-          {
-            composite.red=(MagickRealType) QuantumRange-composite.red;
-            composite.green=(MagickRealType) QuantumRange-composite.green;
-            composite.blue=(MagickRealType) QuantumRange-composite.blue;
-            composite.black=(MagickRealType) QuantumRange-composite.black;
-          }
-        SetPixelRed(image,ClampToQuantum(composite.red),q);
-        SetPixelGreen(image,ClampToQuantum(composite.green),q);
-        SetPixelBlue(image,ClampToQuantum(composite.blue),q);
-        if (image->colorspace == CMYKColorspace)
-          SetPixelBlack(image,ClampToQuantum(composite.black),q);
-        SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
+        q[i]=ClampToQuantum(pixel);
       }
       p+=GetPixelChannels(composite_image);
-      if (p >= (pixels+composite_image->columns*GetPixelChannels(composite_image)))
+      channels=GetPixelChannels(composite_image);
+      if (p >= (pixels+channels*composite_image->columns))
         p=pixels;
       q+=GetPixelChannels(image);
     }
@@ -3016,7 +2283,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);
@@ -3054,7 +2321,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,
@@ -3066,6 +2333,9 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
     *image_view,
     *texture_view;
 
+  Image
+    *texture_image;
+
   MagickBooleanType
     status;
 
@@ -3078,34 +2348,39 @@ 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) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
+    exception);
   status=MagickTrue;
   if ((image->compose != CopyCompositeOp) &&
       ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
-       (texture->matte != MagickFalse)))
+       (texture_image->matte != MagickFalse)))
     {
       /*
         Tile texture onto the image background.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
+      #pragma omp parallel for schedule(static) shared(status)
 #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;
@@ -3118,7 +2393,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);
@@ -3128,16 +2403,17 @@ 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)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3159,34 +2435,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=GetPixelChannelMapChannel(texture_image,i);
+          texture_traits=GetPixelChannelMapTraits(texture_image,channel);
+          traits=GetPixelChannelMapTraits(image,channel);
+          if ((traits == UndefinedPixelTrait) ||
+              (texture_traits == UndefinedPixelTrait))
+            continue;
+          SetPixelChannel(image,channel,p[i],q);
+        }
+        p+=GetPixelChannels(texture_image);
         q+=GetPixelChannels(image);
       }
     }
@@ -3209,5 +2504,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);
 }