]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/composite.c
(no commit message)
[imagemagick] / MagickCore / composite.c
index eea733b16602e8170cce708bf9753a3422f2b64c..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  %
@@ -43,6 +43,7 @@
 #include "MagickCore/studio.h"
 #include "MagickCore/artifact.h"
 #include "MagickCore/cache.h"
+#include "MagickCore/cache-private.h"
 #include "MagickCore/cache-view.h"
 #include "MagickCore/client.h"
 #include "MagickCore/color.h"
@@ -71,7 +72,9 @@
 #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"
 \f
 /*
 %  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)
+%        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.
+%    o exception: return any errors or warnings in this structure.
 %
-%        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"
-%
-*/
-
-static inline double MagickMin(const double x,const double y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-static inline double MagickMax(const double x,const double y)
-{
-  if (x > y)
-    return(x);
-  return(y);
-}
-
-/*
-   Programmers notes on SVG specification.
-  
-   A Composition is defined by...
-     Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
-      Blending areas :  X = 1    for area of overlap   ie: f(Sc,Dc)
-                        Y = 1    for source preserved
-                        Z = 1    for destination preserved
-  
-   Conversion to transparency (then optimized)
-      Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
-      Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
-  
-   Where...
-     Sca = Sc*Sa     normalized Source color divided by Source alpha
-     Dca = Dc*Da     normalized Dest color divided by Dest alpha
-     Dc' = Dca'/Da'  the desired color value for this channel.
-  
-   Da' in in the follow formula as 'gamma'  The resulting alpla value.
-  
-   Most functions use a blending mode of over (X=1,Y=1,Z=1)
-   this results in the following optimizations...
-     gamma = Sa+Da-Sa*Da;
-     gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
-     opacity = QuantiumScale*alpha*beta;  // over blend, optimized 1-Gamma
-  
-   The above SVG definitions also definate that Mathematical Composition
-   methods should use a 'Over' blending mode for Alpha Channel.
-   It however was not applied for composition modes of 'Plus', 'Minus',
-   the modulus versions of 'Add' and 'Subtract'.
-  
-   Mathematical operator changes to be applied from IM v6.7...
-  
-    1/ Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
-       'ModulusAdd' and 'ModulusSubtract' for clarity.
-  
-    2/ All mathematical compositions work as per the SVG specification
-       with regard to blending.  This now includes 'ModulusAdd' and
-       'ModulusSubtract'.
-  
-    3/ When the special channel flag 'sync' (syncronize channel updates)
-       is turned off (enabled by default) then mathematical compositions are
-       only performed on the channels specified, and are applied
-       independantally of each other.  In other words the mathematics is
-       performed as 'pure' mathematical operations, rather than as image
-       operations.
-*/
-
-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);
-}
-
-/*
-  What is this Composition method for? Can't find any specification!
-  WARNING this is not doing correct 'over' blend handling (Anthony Thyssen).
-*/
-static inline void CompositeBumpmap(const 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;
-  if (q->colorspace == CMYKColorspace)
-    composite->black=0.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->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=MagickMin(p->red,q->red);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=MagickMin(p->green,q->green);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=MagickMin(p->blue,q->blue);
-      if ((GetPixelBlackTraits(image) & ActivePixelTrait) != 0 &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=MagickMin(p->black,q->black);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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->sync == MagickFalse)
-    {
-      MagickBooleanType
-        from_p;
-
-      from_p=GetPixelInfoIntensity(p) < GetPixelInfoIntensity(q) ? MagickTrue :
-        MagickFalse;
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=from_p != MagickFalse ? p->red : q->red;
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=from_p != MagickFalse ? p->green : q->green;
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=from_p != MagickFalse ? p->blue : q->blue;
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=from_p != MagickFalse ? p->black : q->black;
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=fabs((double) (p->red-q->red));
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=fabs((double) (p->green-q->green));
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=fabs((double) (p->blue-q->blue));
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=fabs((double) (p->black-q->black));
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=QuantumRange*Divide(QuantumScale*p->red,1.0,
-          QuantumScale*q->red,1.0);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=QuantumRange*Divide(QuantumScale*p->green,1.0,
-          QuantumScale*q->green,1.0);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=QuantumRange*Divide(QuantumScale*p->blue,1.0,
-          QuantumScale*q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Divide(QuantumScale*p->black,1.0,
-          QuantumScale*q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=QuantumRange*Exclusion(QuantumScale*p->red,1.0,
-          QuantumScale*q->red,1.0);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=QuantumRange*Exclusion(QuantumScale*p->green,1.0,
-          QuantumScale*q->green,1.0);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=QuantumRange*Exclusion(QuantumScale*p->blue,1.0,
-          QuantumScale*q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Exclusion(QuantumScale*p->black,1.0,
-          QuantumScale*q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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)
-{
-  MagickRealType
-    delta,
-    max,
-    min;
-
-  /*
-    Convert RGB to HSB colorspace.
-  */
-  assert(hue != (double *) NULL);
-  assert(saturation != (double *) NULL);
-  assert(brightness != (double *) NULL);
-  max=(red > green ? red : green);
-  if (blue > max)
-    max=blue;
-  min=(red < green ? red : green);
-  if (blue < min)
-    min=blue;
-  *hue=0.0;
-  *saturation=0.0;
-  *brightness=(double) (QuantumScale*max);
-  if (max == 0.0)
-    return;
-  *saturation=(double) (1.0-min/max);
-  delta=max-min;
-  if (delta == 0.0)
-    return;
-  if (red == max)
-    *hue=(double) ((green-blue)/delta);
-  else
-    if (green == max)
-      *hue=(double) (2.0+(blue-red)/delta);
-    else
-      if (blue == max)
-        *hue=(double) (4.0+(red-green)/delta);
-  *hue/=6.0;
-  if (*hue < 0.0)
-    *hue+=1.0;
-}
-
-static inline MagickRealType In(const MagickRealType p,const MagickRealType Sa,
-  const MagickRealType magick_unused(q),const MagickRealType Da)
-{
-  return(Sa*p*Da);
-}
-
-static inline void CompositeIn(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;
-  gamma=Sa*Da;
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  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);
-}
-
-static inline MagickRealType Lighten(const MagickRealType p,
-  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
-{
-   if (p > q)
-     return(MagickOver_(p,alpha,q,beta));  /* src-over */
-   return(MagickOver_(q,beta,p,alpha));    /* dst-over */
-}
-
-static inline void CompositeLighten(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    gamma;
-
-  /*
-    Lighten is also equvalent to a 'Maximum' method OR a greyscale version of a
-    binary 'And' OR the 'Union' of pixel sets.
-  */
-  if (image->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=MagickMax(p->red,q->red);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=MagickMax(p->green,q->green);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=MagickMax(p->blue,q->blue);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=MagickMax(p->black,q->black);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        composite->alpha=MagickMin(p->alpha,q->alpha);
-      return;
-    }
-  composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
-  gamma=1.0-QuantumScale*composite->alpha;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Lighten(p->red,p->alpha,q->red,q->alpha);
-  composite->green=gamma*Lighten(p->green,p->alpha,q->green,q->alpha);
-  composite->blue=gamma*Lighten(p->blue,p->alpha,q->blue,q->alpha);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Lighten(p->black,p->alpha,q->black,q->alpha);
-}
-
-static inline void CompositeLightenIntensity(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    Sa;
-
-  /*
-    Select the pixel based on the intensity level.
-    If 'Sync' flag select whole pixel based on alpha weighted intensity.
-    Otherwise use Intenisty only, but restrict copy according to channel.
-  */
-  if (image->sync == MagickFalse)
-    {
-      MagickBooleanType
-        from_p;
-
-      from_p=GetPixelInfoIntensity(p) > GetPixelInfoIntensity(q) ? MagickTrue :
-        MagickFalse;
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=from_p != MagickFalse ? p->red : q->red;
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=from_p != MagickFalse ? p->green : q->green;
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=from_p != MagickFalse ? p->blue : q->blue;
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=from_p != MagickFalse ? p->black : q->black;
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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 void CompositeLinearDodge(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=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);
-}
-
-
-static inline MagickRealType LinearBurn(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    LinearBurn: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
-
-      f(Sc,Dc) = Sc + Dc - 1
-  */
-  return(Sca+Dca-Sa*Da);
-}
-
-static inline void CompositeLinearBurn(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*LinearBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static inline MagickRealType LinearLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  /*
-    LinearLight: as defined by Abode Photoshop, according to
-    http://www.simplefilter.de/en/basics/mixmods.html is:
-
-      f(Sc,Dc) = Dc + 2*Sc - 1
-  */
-  return((Sca-Sa)*Da+Sca+Dca);
-}
-
-static inline void CompositeLinearLight(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*LinearLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*LinearLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*LinearLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*LinearLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
-      q->black*Da,Da);
-}
-
-static inline MagickRealType Mathematics(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
-  const GeometryInfo *geometry_info)
-{
-  MagickRealType
-    gamma;
-
-  /*
-    'Mathematics' a free form user control mathematical composition is defined
-    as...
-
-       f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
-
-    Where the arguments A,B,C,D are (currently) passed to composite as
-    a command separated 'geometry' string in "compose:args" image artifact.
-
-       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->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=QuantumRange*Mathematics(QuantumScale*p->red,1.0,
-          QuantumScale*q->red,1.0,args);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=QuantumRange*Mathematics(QuantumScale*p->green,1.0,
-          QuantumScale*q->green,1.0,args);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=QuantumRange*Mathematics(QuantumScale*p->blue,1.0,
-          QuantumScale*q->blue,1.0,args);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Mathematics(QuantumScale*p->black,1.0,
-          QuantumScale*q->black,1.0,args);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=p->red+q->red;
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=p->green+q->green;
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=p->blue+q->blue;
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=p->black+q->black;
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        composite->alpha=p->alpha+q->alpha-QuantumRange;
-      return;
-    }
-  CompositePixelInfoPlus(p,p->alpha,q,q->alpha,composite);
-}
-
-static inline MagickRealType Minus(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,
-  const MagickRealType magick_unused(Da))
-{
-  /*
-    Minus Source from Destination
-
-      f(Sc,Dc) = Sc - Dc
-  */
-  return(Sca+Dca-2.0*Dca*Sa);
-}
-
-static inline void CompositeMinus(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=p->red-q->red;
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=p->green-q->green;
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=p->blue-q->blue;
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=p->black-q->black;
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-(Sa-Da));
-      return;
-    }
-  gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Minus(p->red*Sa,Sa,q->red*Da,Da);
-  composite->green=gamma*Minus(p->green*Sa,Sa,q->green*Da,Da);
-  composite->blue=gamma*Minus(p->blue*Sa,Sa,q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Minus(p->black*Sa,Sa,q->black*Da,Da);
-}
-
-static inline MagickRealType ModulusAdd(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
-{
-  MagickRealType
-    pixel;
-
-  pixel=p+q;
-  if (pixel > QuantumRange)
-    pixel-=(QuantumRange+1.0);
-  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
-}
-
-static inline void CompositeModulusAdd(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  if (image->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=ModulusAdd(p->red,1.0,q->red,1.0);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=ModulusAdd(p->green,1.0,q->green,1.0);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=ModulusAdd(p->blue,1.0,q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=ModulusAdd(p->black,1.0,q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        composite->alpha=ModulusAdd(p->alpha,1.0,q->alpha,1.0);
-      return;
-    }
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=ModulusAdd(p->red,Sa,q->red,Da);
-  composite->green=ModulusAdd(p->green,Sa,q->green,Da);
-  composite->blue=ModulusAdd(p->blue,Sa,q->blue,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=ModulusAdd(p->black,Sa,q->black,Da);
-}
-
-static inline MagickRealType ModulusSubtract(const MagickRealType p,
-  const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
-{
-  MagickRealType
-    pixel;
-
-  pixel=p-q;
-  if (pixel < 0.0)
-    pixel+=(QuantumRange+1.0);
-  return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
-}
-
-static inline void CompositeModulusSubtract(const Image *image,
-  const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  if (image->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels,
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=ModulusSubtract(p->red,1.0,q->red,1.0);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=ModulusSubtract(p->green,1.0,q->green,1.0);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=ModulusSubtract(p->blue,1.0,q->blue,1.0);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=ModulusSubtract(p->black,1.0,q->black,1.0);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        composite->alpha=ModulusSubtract(p->alpha,1.0,q->alpha,1.0);
-      return;
-    }
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  gamma = RoundToUnity(Sa+Da-Sa*Da);
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=ModulusSubtract(p->red,Sa,q->red,Da);
-  composite->green=ModulusSubtract(p->green,Sa,q->green,Da);
-  composite->blue=ModulusSubtract(p->blue,Sa,q->blue,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=ModulusSubtract(p->black,Sa,q->black,Da);
-}
-
-static  inline MagickRealType Multiply(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  return(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
-}
-
-static inline void CompositeMultiply(const Image *image,const PixelInfo *p,
-  const PixelInfo *q,PixelInfo *composite)
-{
-  MagickRealType
-    Da,
-    gamma,
-    Sa;
-
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=QuantumScale*p->red*q->red;
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=QuantumScale*p->green*q->green;
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=QuantumScale*p->blue*q->blue;
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumScale*p->black*q->black;
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 0)
-        composite->alpha=QuantumRange*(1.0-Sa*Da);
-      return;
-    }
-  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
-  composite->alpha=(MagickRealType) QuantumRange*gamma;
-  gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
-    q->red*Da,Da);
-  composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
-    q->green*Da,Da);
-  composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
-    q->blue*Da,Da);
-  if (q->colorspace == CMYKColorspace)
-    composite->black=gamma*Multiply(QuantumScale*p->black*Sa,Sa,
-      QuantumScale*q->black*Da,Da);
-}
-
-static inline MagickRealType Out(const MagickRealType p,const MagickRealType Sa,
-  const MagickRealType magick_unused(q),const MagickRealType Da)
-{
-  return(Sa*p*(1.0-Da));
-}
-
-static inline void CompositeOut(const PixelInfo *p,const PixelInfo *q,
-  PixelInfo *composite)
-{
-  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);
-}
-
-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;
+/*
+   Composition based on the SVG specification:
 
-  Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
-  Da=QuantumScale*q->alpha;
-  if (image->sync == MagickFalse)
-    {
-      /*
-        Handle channels as separate grayscale channels.
-      */
-      if ((GetPixelRedTraits(image) & ActivePixelTrait) != 0)
-        composite->red=QuantumRange*Screen(QuantumScale*p->red,
-          QuantumScale*q->red);
-      if ((GetPixelGreenTraits(image) & ActivePixelTrait) != 0)
-        composite->green=QuantumRange*Screen(QuantumScale*p->green,
-          QuantumScale*q->green);
-      if ((GetPixelBlueTraits(image) & ActivePixelTrait) != 0)
-        composite->blue=QuantumRange*Screen(QuantumScale*p->blue,
-          QuantumScale*q->blue);
-      if (((GetPixelBlackTraits(image) & ActivePixelTrait) != 0) &&
-          (q->colorspace == CMYKColorspace))
-        composite->black=QuantumRange*Screen(QuantumScale*p->black,
-          QuantumScale*q->black);
-      if ((GetPixelAlphaTraits(image) & ActivePixelTrait) != 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);
-}
+   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
 
-static MagickRealType SoftLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
-{
-  MagickRealType
-    alpha,
-    beta;
+   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)
 
-  /*
-    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);
-}
+   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.
 
-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);
-}
+   Da' in in the follow formula as 'gamma'  The resulting alpla value.
 
-static inline MagickRealType Threshold(const MagickRealType p,
-  const MagickRealType q,const MagickRealType threshold,
-  const MagickRealType amount)
-{
-  MagickRealType
-    delta;
+   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
 
-  /*
-    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
+   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'.
 
-    Deprecated.
-  */
-  delta=p-q;
-  if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
-    return(q);
-  return(q+delta*amount);
-}
+   Mathematical operator changes to be applied from IM v6.7...
 
-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);
-}
+    1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
+       'ModulusAdd' and 'ModulusSubtract' for clarity.
 
+    2) All mathematical compositions work as per the SVG specification
+       with regard to blending.  This now includes 'ModulusAdd' and
+       'ModulusSubtract'.
 
-static MagickRealType VividLight(const MagickRealType Sca,
-  const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
+    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 void CompositeHSB(const double red,const double green,
+  const double blue,double *hue,double *saturation,double *brightness)
 {
-  /*
-    VividLight: A Photoshop 7 composition method.  See
-    http://www.simplefilter.de/en/basics/mixmods.html.
+  double
+    delta,
+    max,
+    min;
 
-    f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
+  /*
+    Convert RGB to HSB colorspace.
   */
-  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);
+  assert(hue != (double *) NULL);
+  assert(saturation != (double *) NULL);
+  assert(brightness != (double *) NULL);
+  max=(red > green ? red : green);
+  if (blue > max)
+    max=blue;
+  min=(red < green ? red : green);
+  if (blue < min)
+    min=blue;
+  *hue=0.0;
+  *saturation=0.0;
+  *brightness=(double) (QuantumScale*max);
+  if (fabs((double) max) < MagickEpsilon)
+    return;
+  *saturation=(double) (1.0-min/max);
+  delta=(MagickRealType) max-min;
+  if (fabs(delta) < MagickEpsilon)
+    return;
+  if (fabs((double) red-max) < MagickEpsilon)
+    *hue=(double) ((green-blue)/delta);
+  else
+    if (fabs((double) green-max) < MagickEpsilon)
+      *hue=(double) (2.0+(blue-red)/delta);
+    else
+      if (fabs((double) blue-max) < MagickEpsilon)
+        *hue=(double) (4.0+(red-green)/delta);
+  *hue/=6.0;
+  if (*hue < 0.0)
+    *hue+=1.0;
 }
 
 static void HSBComposite(const double hue,const double saturation,
-  const double brightness,MagickRealType *red,MagickRealType *green,
-  MagickRealType *blue)
+  const double brightness,double *red,double *green,double *blue)
 {
-  MagickRealType
+  double
     f,
     h,
     p,
@@ -1479,12 +230,12 @@ static void HSBComposite(const double hue,const double saturation,
   /*
     Convert HSB to RGB colorspace.
   */
-  assert(red != (MagickRealType *) NULL);
-  assert(green != (MagickRealType *) NULL);
-  assert(blue != (MagickRealType *) NULL);
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
   if (saturation == 0.0)
     {
-      *red=(MagickRealType) QuantumRange*brightness;
+      *red=(double) QuantumRange*brightness;
       *green=(*red);
       *blue=(*red);
       return;
@@ -1499,52 +250,66 @@ static void HSBComposite(const double hue,const double saturation,
     case 0:
     default:
     {
-      *red=(MagickRealType) QuantumRange*brightness;
-      *green=(MagickRealType) QuantumRange*t;
-      *blue=(MagickRealType) QuantumRange*p;
+      *red=(double) QuantumRange*brightness;
+      *green=(double) QuantumRange*t;
+      *blue=(double) QuantumRange*p;
       break;
     }
     case 1:
     {
-      *red=(MagickRealType) QuantumRange*q;
-      *green=(MagickRealType) QuantumRange*brightness;
-      *blue=(MagickRealType) QuantumRange*p;
+      *red=(double) QuantumRange*q;
+      *green=(double) QuantumRange*brightness;
+      *blue=(double) QuantumRange*p;
       break;
     }
     case 2:
     {
-      *red=(MagickRealType) QuantumRange*p;
-      *green=(MagickRealType) QuantumRange*brightness;
-      *blue=(MagickRealType) QuantumRange*t;
+      *red=(double) QuantumRange*p;
+      *green=(double) QuantumRange*brightness;
+      *blue=(double) QuantumRange*t;
       break;
     }
     case 3:
     {
-      *red=(MagickRealType) QuantumRange*p;
-      *green=(MagickRealType) QuantumRange*q;
-      *blue=(MagickRealType) QuantumRange*brightness;
+      *red=(double) QuantumRange*p;
+      *green=(double) QuantumRange*q;
+      *blue=(double) QuantumRange*brightness;
       break;
     }
     case 4:
     {
-      *red=(MagickRealType) QuantumRange*t;
-      *green=(MagickRealType) QuantumRange*p;
-      *blue=(MagickRealType) QuantumRange*brightness;
+      *red=(double) QuantumRange*t;
+      *green=(double) QuantumRange*p;
+      *blue=(double) QuantumRange*brightness;
       break;
     }
     case 5:
     {
-      *red=(MagickRealType) QuantumRange*brightness;
-      *green=(MagickRealType) QuantumRange*p;
-      *blue=(MagickRealType) QuantumRange*q;
+      *red=(double) QuantumRange*brightness;
+      *green=(double) QuantumRange*p;
+      *blue=(double) QuantumRange*q;
       break;
     }
   }
 }
 
-MagickExport MagickBooleanType CompositeImage(Image *image,
-  const CompositeOperator compose,const Image *composite_image,
-  const ssize_t x_offset,const ssize_t y_offset)
+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);
+}
+
+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)
 {
 #define CompositeImageTag  "Composite/Image"
 
@@ -1552,14 +317,230 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     *composite_view,
     *image_view;
 
-  const char
-    *value;
+  MagickBooleanType
+    status;
 
-  double
-    sans;
+  MagickOffsetType
+    progress;
+
+  ssize_t
+    y;
+
+  /*
+    Composite image.
+  */
+  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;
+
+    register const Quantum
+      *restrict p;
 
-  ExceptionInfo
-    *exception;
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    size_t
+      channels;
+
+    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++)
+    {
+      MagickRealType
+        alpha,
+        Da,
+        Dc,
+        gamma,
+        Sa,
+        Sc;
+
+      register ssize_t
+        i;
+
+      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];
+
+          /*
+            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;
+        }
+      /*
+        Authentic composite:
+          Sa:  normalized source alpha.
+          Da:  normalized destination alpha.
+      */
+      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);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+    if (image->progress_monitor != (MagickProgressMonitor) NULL)
+      {
+        MagickBooleanType
+          proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp critical (MagickCore_CompositeImage)
+#endif
+        proceed=SetImageProgress(image,CompositeImageTag,progress++,
+          image->rows);
+        if (proceed == MagickFalse)
+          status=MagickFalse;
+      }
+  }
+  composite_view=DestroyCacheView(composite_view);
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+MagickExport MagickBooleanType CompositeImage(Image *image,
+  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"
+
+  CacheView
+    *composite_view,
+    *image_view;
 
   GeometryInfo
     geometry_info;
@@ -1568,15 +549,11 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     *destination_image;
 
   MagickBooleanType
-    modify_outside_overlay,
     status;
 
   MagickOffsetType
     progress;
 
-  PixelInfo
-    zero;
-
   MagickRealType
     amount,
     destination_dissolve,
@@ -1592,43 +569,32 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
   ssize_t
     y;
 
-  /*
-    Prepare composite image.
-  */
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(composite_image != (Image *) NULL);
   assert(composite_image->signature == MagickSignature);
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
-  GetPixelInfo(image,&zero);
+  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 SrcCompositeOp:
-    case InCompositeOp:
-    case SrcInCompositeOp:
-    case OutCompositeOp:
-    case SrcOutCompositeOp:
-    case DstInCompositeOp:
-    case DstAtopCompositeOp:
-    {
-      /*
-        Modify destination outside the overlaid region.
-      */
-      modify_outside_overlay=MagickTrue;
-      break;
-    }
     case CopyCompositeOp:
     {
       if ((x_offset < 0) || (y_offset < 0))
@@ -1638,11 +604,10 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
         break;
       status=MagickTrue;
-      exception=(&image->exception);
-      image_view=AcquireCacheView(image);
-      composite_view=AcquireCacheView(composite_image);
+      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++)
       {
@@ -1669,16 +634,36 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
             status=MagickFalse;
             continue;
           }
-        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);
-          p+=GetPixelComponents(composite_image);
-          q+=GetPixelComponents(image);
+        for (x=0; x < (ssize_t) composite_image->columns; x++)
+        {
+          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);
         }
         sync=SyncCacheViewAuthenticPixels(image_view,exception);
         if (sync == MagickFalse)
@@ -1689,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);
@@ -1701,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);
-      modify_outside_overlay=MagickTrue;
+        {
+          (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+          image->matte=MagickFalse;
+        }
       break;
     }
     case BlurCompositeOp:
@@ -1719,6 +707,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         *composite_view,
         *destination_view;
 
+      const char
+        *value;
+
       PixelInfo
         pixel;
 
@@ -1735,36 +726,45 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         blur;
 
       /*
+        Blur Image by resampling.
+
         Blur Image dictated by an overlay gradient map: X = red_channel;
           Y = green_channel; compose:args =  x_scale[,y_scale[,angle]].
       */
       destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
-        &image->exception);
+        exception);
       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
@@ -1776,20 +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.
       */
-      pixel=zero;
-      exception=(&image->exception);
-      resample_filter=AcquireResampleFilter(image,&image->exception);
-      SetResampleFilter(resample_filter,CubicFilter,2.0);
-      destination_view=AcquireCacheView(destination_image);
-      composite_view=AcquireCacheView(composite_image);
+      resample_filter=AcquireResampleFilter(image,exception);
+      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
@@ -1809,14 +821,14 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
           1,exception);
         q=QueueCacheViewAuthenticPixels(destination_view,0,y,
-          destination_image->columns,1,&image->exception);
+          destination_image->columns,1,exception);
         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
           break;
         for (x=0; x < (ssize_t) composite_image->columns; x++)
         {
           if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
             {
-              p+=GetPixelComponents(composite_image);
+              p+=GetPixelChannels(composite_image);
               continue;
             }
           if (fabs(angle_range) > MagickEpsilon)
@@ -1831,16 +843,23 @@ 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);
-          SetPixelPixelInfo(destination_image,&pixel,q);
-          p+=GetPixelComponents(composite_image);
-          q+=GetPixelComponents(destination_image);
+            (double) y_offset+y,&pixel,exception);
+          SetPixelInfoPixel(destination_image,&pixel,q);
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(destination_image);
         }
         sync=SyncCacheViewAuthenticPixels(destination_view,exception);
         if (sync == MagickFalse)
@@ -1860,6 +879,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         *destination_view,
         *image_view;
 
+      const char
+        *value;
+
       PixelInfo
         pixel;
 
@@ -1877,7 +899,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
           compose:args = x_scale[,y_scale[,center.x,center.y]]
       */
       destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
-        &image->exception);
+        exception);
       if (destination_image == (Image *) NULL)
         return(MagickFalse);
       SetGeometryInfo(&geometry_info);
@@ -1957,11 +979,10 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         Shift the pixel offset point as defined by the provided,
         displacement/distortion map.  -- Like a lens...
       */
-      pixel=zero;
-      exception=(&image->exception);
-      image_view=AcquireCacheView(image);
-      destination_view=AcquireCacheView(destination_image);
-      composite_view=AcquireCacheView(composite_image);
+      GetPixelInfo(image,&pixel);
+      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
@@ -1981,14 +1002,14 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
         p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
           1,exception);
         q=QueueCacheViewAuthenticPixels(destination_view,0,y,
-          destination_image->columns,1,&image->exception);
+          destination_image->columns,1,exception);
         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
           break;
         for (x=0; x < (ssize_t) composite_image->columns; x++)
         {
           if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
             {
-              p+=GetPixelComponents(composite_image);
+              p+=GetPixelChannels(composite_image);
               continue;
             }
           /*
@@ -2009,11 +1030,10 @@ 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)));
-          SetPixelPixelInfo(destination_image,&pixel,q);
-          p+=GetPixelComponents(composite_image);
-          q+=GetPixelComponents(destination_image);
+            pixel.alpha)*(1.0-QuantumScale*GetPixelAlpha(composite_image,p)));
+          SetPixelInfoPixel(destination_image,&pixel,q);
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(destination_image);
         }
         sync=SyncCacheViewAuthenticPixels(destination_view,exception);
         if (sync == MagickFalse)
@@ -2027,6 +1047,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case DissolveCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Geometry arguments to dissolve factors.
       */
@@ -2047,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)
         {
@@ -2066,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.
@@ -2090,6 +1118,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case ModulateCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Determine the brightness and saturation scale.
       */
@@ -2105,6 +1136,9 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
     }
     case ThresholdCompositeOp:
     {
+      const char
+        *value;
+
       /*
         Determine the amount and threshold.
       */
@@ -2123,21 +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;
-  GetPixelInfo(composite_image,&zero);
-  exception=(&image->exception);
-  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++)
   {
@@ -2145,14 +1174,16 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
       *pixels;
 
     double
+      blue,
       brightness,
+      green,
       hue,
+      red,
       saturation;
 
     PixelInfo
-      composite,
-      destination,
-      source;
+      destination_pixel,
+      source_pixel;
 
     register const Quantum
       *restrict p;
@@ -2165,7 +1196,7 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
 
     if (status == MagickFalse)
       continue;
-    if (modify_outside_overlay == MagickFalse)
+    if (clip_to_self != MagickFalse)
       {
         if (y < y_offset)
           continue;
@@ -2188,515 +1219,1061 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
           }
         pixels=p;
         if (x_offset < 0)
-          p-=x_offset*GetPixelComponents(composite_image);
+          p-=x_offset*GetPixelChannels(composite_image);
       }
     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
-    if (q == (const Quantum *) NULL)
+    if (q == (Quantum *) NULL)
       {
         status=MagickFalse;
         continue;
       }
-    source=zero;
-    destination=zero;
     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)
             {
-              q+=GetPixelComponents(image);
+              q+=GetPixelChannels(image);
               continue;
             }
           if ((x-x_offset) >= (ssize_t) composite_image->columns)
             break;
         }
-      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:
-            {
-              composite.alpha=destination_dissolve*(composite.alpha);
-              break;
-            }
-            case ClearCompositeOp:
-            case SrcCompositeOp:
-            {
-              CompositeClear(&destination,&composite);
-              break;
-            }
-            case InCompositeOp:
-            case SrcInCompositeOp:
-            case OutCompositeOp:
-            case SrcOutCompositeOp:
-            case DstInCompositeOp:
-            case DstAtopCompositeOp:
-            case CopyOpacityCompositeOp:
-            case ChangeMaskCompositeOp:
+          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)
             {
-              composite.alpha=(MagickRealType) TransparentAlpha;
-              break;
+              q+=GetPixelChannels(image);
+              continue;
             }
-            default:
+          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)
             {
-              (void) GetOneVirtualMagickPixel(composite_image,x-x_offset,y-
-                y_offset,&composite,exception);
-              break;
+              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);
           }
-          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->matte != MagickFalse)
-            SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
-          if (image->colorspace == CMYKColorspace)
-            SetPixelBlack(image,ClampToQuantum(composite.black),q);
-          q+=GetPixelComponents(image);
+          q+=GetPixelChannels(image);
           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.
+        Authentic composite:
+          Sa:  normalized source alpha.
+          Da:  normalized destination alpha.
       */
+      Sa=QuantumScale*GetPixelAlpha(composite_image,p);
+      Da=QuantumScale*GetPixelAlpha(image,q);
       switch (compose)
       {
-        case ClearCompositeOp:
-        {
-          CompositeClear(&destination,&composite);
-          break;
-        }
-        case SrcCompositeOp:
-        case CopyCompositeOp:
-        case ReplaceCompositeOp:
-        {
-          composite=source;
-          break;
-        }
-        case NoCompositeOp:
-        case DstCompositeOp:
-          break;
-        case OverCompositeOp:
-        case SrcOverCompositeOp:
-        {
-          CompositePixelInfoOver(&source,source.alpha,&destination,
-            destination.alpha,&composite);
-          break;
-        }
-        case DstOverCompositeOp:
-        {
-          CompositePixelInfoOver(&destination,destination.alpha,&source,
-            source.alpha,&composite);
-          break;
-        }
-        case SrcInCompositeOp:
-        case InCompositeOp:
-        {
-          CompositeIn(&source,&destination,&composite);
-          break;
-        }
-        case DstInCompositeOp:
-        {
-          CompositeIn(&destination,&source,&composite);
-          break;
-        }
-        case OutCompositeOp:
-        case SrcOutCompositeOp:
-        {
-          CompositeOut(&source,&destination,&composite);
-          break;
-        }
-        case DstOutCompositeOp:
-        {
-          CompositeOut(&destination,&source,&composite);
-          break;
-        }
-        case AtopCompositeOp:
-        case SrcAtopCompositeOp:
-        {
-          CompositeAtop(&source,&destination,&composite);
-          break;
-        }
-        case DstAtopCompositeOp:
-        {
-          CompositeAtop(&destination,&source,&composite);
-          break;
-        }
-        case XorCompositeOp:
-        {
-          CompositeXor(&source,&destination,&composite);
-          break;
-        }
-        case PlusCompositeOp:
+        case BumpmapCompositeOp:
         {
-          CompositePlus(image,&source,&destination,&composite);
+          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:
-        {
-          CompositeMinus(image,&source,&destination,&composite);
-          break;
-        }
         case MinusSrcCompositeOp:
-        {
-          CompositeMinus(image,&destination,&source,&composite);
-          break;
-        }
         case ModulusAddCompositeOp:
-        {
-          CompositeModulusAdd(image,&source,&destination,&composite);
-          break;
-        }
         case ModulusSubtractCompositeOp:
-        {
-          CompositeModulusSubtract(image,&source,&destination,&composite);
-          break;
-        }
-        case DifferenceCompositeOp:
-        {
-          CompositeDifference(image,&source,&destination,&composite);
-          break;
-        }
-        case ExclusionCompositeOp:
-        {
-          CompositeExclusion(image,&source,&destination,&composite);
-          break;
-        }
         case MultiplyCompositeOp:
-        {
-          CompositeMultiply(image,&source,&destination,&composite);
-          break;
-        }
-        case ScreenCompositeOp:
-        {
-          CompositeScreen(image,&source,&destination,&composite);
-          break;
-        }
-        case DivideDstCompositeOp:
-        {
-          CompositeDivide(image,&source,&destination,&composite);
-          break;
-        }
-        case DivideSrcCompositeOp:
-        {
-          CompositeDivide(image,&destination,&source,&composite);
-          break;
-        }
-        case DarkenCompositeOp:
-        {
-          CompositeDarken(image,&source,&destination,&composite);
-          break;
-        }
-        case LightenCompositeOp:
-        {
-          CompositeLighten(image,&source,&destination,&composite);
-          break;
-        }
-        case DarkenIntensityCompositeOp:
-        {
-          CompositeDarkenIntensity(image,&source,&destination,&composite);
-          break;
-        }
-        case LightenIntensityCompositeOp:
-        {
-          CompositeLightenIntensity(image,&source,&destination,&composite);
-          break;
-        }
-        case MathematicsCompositeOp:
-        {
-          CompositeMathematics(image,&source,&destination,&geometry_info,
-            &composite);
-          break;
-        }
-        case ColorDodgeCompositeOp:
-        {
-          CompositeColorDodge(&source,&destination,&composite);
-          break;
-        }
-        case ColorBurnCompositeOp:
-        {
-          CompositeColorBurn(&source,&destination,&composite);
-          break;
-        }
-        case LinearDodgeCompositeOp:
-        {
-          CompositeLinearDodge(&source,&destination,&composite);
-          break;
-        }
-        case LinearBurnCompositeOp:
-        {
-          CompositeLinearBurn(&source,&destination,&composite);
-          break;
-        }
-        case HardLightCompositeOp:
-        {
-          CompositeHardLight(&source,&destination,&composite);
-          break;
-        }
         case OverlayCompositeOp:
-        {
-          CompositeHardLight(&destination,&source,&composite);
-          break;
-        }
-        case SoftLightCompositeOp:
-        {
-          CompositeSoftLight(&source,&destination,&composite);
-          break;
-        }
-        case LinearLightCompositeOp:
-        {
-          CompositeLinearLight(&source,&destination,&composite);
-          break;
-        }
         case PegtopLightCompositeOp:
-        {
-          CompositePegtopLight(&source,&destination,&composite);
-          break;
-        }
-        case VividLightCompositeOp:
-        {
-          CompositeVividLight(&source,&destination,&composite);
-          break;
-        }
         case PinLightCompositeOp:
+        case ScreenCompositeOp:
+        case SoftLightCompositeOp:
+        case VividLightCompositeOp:
         {
-          CompositePinLight(&source,&destination,&composite);
-          break;
-        }
-        case ChangeMaskCompositeOp:
-        {
-          if ((composite.alpha > ((MagickRealType) QuantumRange/2.0)) ||
-              (IsFuzzyEquivalencePixelInfo(&source,&destination) != MagickFalse))
-            composite.alpha=(MagickRealType) TransparentAlpha;
-          else
-            composite.alpha=(MagickRealType) OpaqueAlpha;
-          break;
-        }
-        case BumpmapCompositeOp:
-        {
-          if (source.alpha == TransparentAlpha)
-            break;
-          CompositeBumpmap(&source,&destination,&composite);
-          break;
-        }
-        case DissolveCompositeOp:
-        {
-          CompositePixelInfoOver(&source,source_dissolve*source.alpha,
-            &destination,(MagickRealType) (destination_dissolve*
-            destination.alpha),&composite);
-          break;
-        }
-        case BlendCompositeOp:
-        {
-          CompositePixelInfoBlend(&source,source_dissolve,&destination,
-            destination_dissolve,&composite);
-          break;
-        }
-        case ThresholdCompositeOp:
-        {
-          CompositeThreshold(&source,&destination,threshold,amount,&composite);
-          break;
-        }
-        case ModulateCompositeOp:
-        {
-          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,&composite.red,
-            &composite.green,&composite.blue);
+          alpha=RoundToUnity(Sa+Da-Sa*Da);
           break;
         }
-        case HueCompositeOp:
+        case DarkenCompositeOp:
+        case DstAtopCompositeOp:
+        case DstInCompositeOp:
+        case InCompositeOp:
+        case LightenCompositeOp:
+        case SrcInCompositeOp:
         {
-          if (source.alpha == TransparentAlpha)
-            break;
-          if (destination.alpha == TransparentAlpha)
-            {
-              composite=source;
-              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;
+          alpha=Sa*Da;
           break;
         }
-        case SaturateCompositeOp:
-        {
-          if (source.alpha == TransparentAlpha)
-            break;
-          if (destination.alpha == TransparentAlpha)
-            {
-              composite=source;
-              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;
+        case DissolveCompositeOp:
+        {
+          alpha=source_dissolve*Sa*(-destination_dissolve*Da)+source_dissolve*
+            Sa+destination_dissolve*Da;
           break;
         }
-        case LuminizeCompositeOp:
+        case DstOverCompositeOp:
         {
-          if (source.alpha == TransparentAlpha)
-            break;
-          if (destination.alpha == TransparentAlpha)
-            {
-              composite=source;
-              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;
+          alpha=Da*(-Sa)+Da+Sa;
           break;
         }
-        case ColorizeCompositeOp:
+        case DstOutCompositeOp:
         {
-          if (source.alpha == TransparentAlpha)
-            break;
-          if (destination.alpha == TransparentAlpha)
-            {
-              composite=source;
-              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;
+          alpha=Da*(1.0-Sa);
           break;
         }
-        case CopyRedCompositeOp:
-        case CopyCyanCompositeOp:
+        case OutCompositeOp:
+        case SrcOutCompositeOp:
         {
-          composite.red=source.red;
+          alpha=Sa*(1.0-Da);
           break;
         }
-        case CopyGreenCompositeOp:
-        case CopyMagentaCompositeOp:
+        case OverCompositeOp:
+        case SrcOverCompositeOp:
         {
-          composite.green=source.green;
+          alpha=Sa*(-Da)+Sa+Da;
           break;
         }
-        case CopyBlueCompositeOp:
-        case CopyYellowCompositeOp:
+        case BlendCompositeOp:
+        case PlusCompositeOp:
         {
-          composite.blue=source.blue;
+          alpha=RoundToUnity(Sa+Da);
           break;
         }
-        case CopyOpacityCompositeOp:
+        case XorCompositeOp:
         {
-          if (source.matte == MagickFalse)
-            {
-              composite.alpha=(MagickRealType) GetPixelInfoIntensity(&source);
-              break;
-            }
-          composite.alpha=source.alpha;
+          alpha=Sa+Da-2.0*Sa*Da;
           break;
         }
-        case CopyBlackCompositeOp:
+        default:
         {
-          if (source.colorspace != CMYKColorspace)
-            ConvertRGBToCMYK(&source);
-          composite.black=source.black;
+          alpha=1.0;
           break;
         }
-        case BlurCompositeOp:
-        case DisplaceCompositeOp:
-        case DistortCompositeOp:
+      }
+      if (GetPixelMask(image,p) != 0)
+        {
+          p+=GetPixelChannels(composite_image);
+          q+=GetPixelChannels(image);
+          continue;
+        }
+      switch (compose)
+      {
+        case ColorizeCompositeOp:
+        case HueCompositeOp:
+        case LuminizeCompositeOp:
+        case ModulateCompositeOp:
+        case SaturateCompositeOp:
         {
-          composite=source;
+          GetPixelInfoPixel(composite_image,p,&source_pixel);
+          GetPixelInfoPixel(image,q,&destination_pixel);
           break;
         }
         default:
           break;
       }
-      if (image->colorspace == CMYKColorspace)
+      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+      {
+        double
+          sans;
+
+        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)
+          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;
+              }
+            /*
+              Set alpha channel.
+            */
+            switch (compose)
+            {
+              case AlphaCompositeOp:
+              {
+                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;
+                  }
+                equivalent=IsFuzzyEquivalencePixel(composite_image,p,image,q);
+                if (equivalent != MagickFalse)
+                  {
+                    pixel=(MagickRealType) TransparentAlpha;
+                    break;
+                  }
+                pixel=(MagickRealType) OpaqueAlpha;
+                break;
+              }
+              case ClearCompositeOp:
+              {
+                pixel=(MagickRealType) TransparentAlpha;
+                break;
+              }
+              case ColorizeCompositeOp:
+              case HueCompositeOp:
+              case LuminizeCompositeOp:
+              case SaturateCompositeOp:
+              {
+                if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+                  {
+                    pixel=QuantumRange*Da;
+                    break;
+                  }
+                if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+                  {
+                    pixel=QuantumRange*Sa;
+                    break;
+                  }
+                if (Sa < Da)
+                  {
+                    pixel=QuantumRange*Da;
+                    break;
+                  }
+                pixel=QuantumRange*Sa;
+                break;
+              }
+              case CopyCompositeOp:
+              case CopyAlphaCompositeOp:
+              case DisplaceCompositeOp:
+              case DistortCompositeOp:
+              case DstAtopCompositeOp:
+              case ReplaceCompositeOp:
+              case SrcCompositeOp:
+              {
+                pixel=QuantumRange*Sa;
+                break;
+              }
+              case DarkenIntensityCompositeOp:
+              {
+                pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
+                  (1.0-Da)*GetPixelIntensity(image,q) ? Sa : Da;
+                break;
+              }
+              case IntensityCompositeOp:
+              {
+                pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
+                break;
+              }
+              case LightenIntensityCompositeOp:
+              {
+                pixel=Sa*GetPixelIntensity(composite_image,p) >
+                  Da*GetPixelIntensity(image,q) ? Sa : Da;
+                break;
+              }
+              case ModulateCompositeOp:
+              {
+                if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+                  {
+                    pixel=QuantumRange*Da;
+                    break;
+                  }
+                pixel=QuantumRange*Da;
+                break;
+              }
+              default:
+              {
+                pixel=QuantumRange*alpha;
+                break;
+              }
+            }
+            q[i]=ClampToQuantum(pixel);
+            continue;
+          }
+        /*
+          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 DarkenCompositeOp:
+          case LightenCompositeOp:
+          case ModulusSubtractCompositeOp:
+          {
+            gamma=1.0-alpha;
+            break;
+          }
+          default:
+            break;
+        }
+        gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
+        pixel=Dc;
+        switch (compose)
         {
-          composite.red=(MagickRealType) QuantumRange-composite.red;
-          composite.green=(MagickRealType) QuantumRange-composite.green;
-          composite.blue=(MagickRealType) QuantumRange-composite.blue;
-          composite.black=(MagickRealType) QuantumRange-composite.black;
+          case AlphaCompositeOp:
+          {
+            pixel=QuantumRange*Sa;
+            break;
+          }
+          case AtopCompositeOp:
+          case SrcAtopCompositeOp:
+          {
+            pixel=Sc*Sa+Dc*(1.0-Sa);
+            break;
+          }
+          case BlendCompositeOp:
+          {
+            pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
+            break;
+          }
+          case BlurCompositeOp:
+          case DisplaceCompositeOp:
+          case DistortCompositeOp:
+          case CopyCompositeOp:
+          case ReplaceCompositeOp:
+          case SrcCompositeOp:
+          {
+            pixel=Sc;
+            break;
+          }
+          case BumpmapCompositeOp:
+          {
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
+            break;
+          }
+          case ChangeMaskCompositeOp:
+          {
+            pixel=Dc;
+            break;
+          }
+          case ClearCompositeOp:
+          {
+            pixel=0.0;
+            break;
+          }
+          case ColorBurnCompositeOp:
+          {
+            /*
+              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 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:
+          {
+            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 CopyAlphaCompositeOp:
+          case IntensityCompositeOp:
+          {
+            if (channel == AlphaPixelChannel)
+              pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
+            break;
+          }
+          case CopyBlackCompositeOp:
+          {
+            if (channel == BlackPixelChannel)
+              pixel=(MagickRealType) GetPixelBlack(composite_image,p);
+            break;
+          }
+          case CopyBlueCompositeOp:
+          case CopyYellowCompositeOp:
+          {
+            if (channel == BluePixelChannel)
+              pixel=(MagickRealType) GetPixelBlue(composite_image,p);
+            break;
+          }
+          case CopyGreenCompositeOp:
+          case CopyMagentaCompositeOp:
+          {
+            if (channel == GreenPixelChannel)
+              pixel=(MagickRealType) GetPixelGreen(composite_image,p);
+            break;
+          }
+          case CopyRedCompositeOp:
+          case CopyCyanCompositeOp:
+          {
+            if (channel == RedPixelChannel)
+              pixel=(MagickRealType) GetPixelRed(composite_image,p);
+            break;
+          }
+          case DarkenCompositeOp:
+          {
+            /*
+              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 DarkenIntensityCompositeOp:
+          {
+            pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
+              (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
+            break;
+          }
+          case DifferenceCompositeOp:
+          {
+            pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
+            break;
+          }
+          case DissolveCompositeOp:
+          {
+            pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
+              destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
+            break;
+          }
+          case DivideDstCompositeOp:
+          {
+            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 DivideSrcCompositeOp:
+          {
+            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 DstAtopCompositeOp:
+          {
+            pixel=Dc*Da+Sc*(1.0-Da);
+            break;
+          }
+          case DstCompositeOp:
+          case NoCompositeOp:
+          {
+            pixel=Dc;
+            break;
+          }
+          case DstInCompositeOp:
+          {
+            pixel=gamma*(Sa*Dc*Sa);
+            break;
+          }
+          case DstOutCompositeOp:
+          {
+            pixel=gamma*(Da*Dc*(1.0-Sa));
+            break;
+          }
+          case DstOverCompositeOp:
+          {
+            pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
+            break;
+          }
+          case ExclusionCompositeOp:
+          {
+            pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
+            break;
+          }
+          case HardLightCompositeOp:
+          {
+            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 HueCompositeOp:
+          {
+            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 InCompositeOp:
+          case SrcInCompositeOp:
+          {
+            pixel=gamma*(Da*Sc*Da);
+            break;
+          }
+          case LinearBurnCompositeOp:
+          {
+            /*
+              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 LinearDodgeCompositeOp:
+          {
+            pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
+            break;
+          }
+          case LinearLightCompositeOp:
+          {
+            /*
+              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 LightenCompositeOp:
+          {
+            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 LightenIntensityCompositeOp:
+          {
+            /*
+              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 LuminizeCompositeOp:
+          {
+            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 MathematicsCompositeOp:
+          {
+            /*
+              '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 MinusDstCompositeOp:
+          {
+            pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
+            break;
+          }
+          case MinusSrcCompositeOp:
+          {
+            /*
+              Minus source from destination.
+
+                f(Sc,Dc) = Sc - Dc
+            */
+            pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
+            break;
+          }
+          case ModulateCompositeOp:
+          {
+            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 ModulusAddCompositeOp:
+          {
+            pixel=Sc+Dc;
+            if (pixel > QuantumRange)
+              pixel-=(QuantumRange+1.0);
+            pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
+            break;
+          }
+          case ModulusSubtractCompositeOp:
+          {
+            pixel=Sc-Dc;
+            if (pixel < 0.0)
+              pixel+=(QuantumRange+1.0);
+            pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
+            break;
+          }
+          case MultiplyCompositeOp:
+          {
+            pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
+            break;
+          }
+          case OutCompositeOp:
+          case SrcOutCompositeOp:
+          {
+            pixel=gamma*(Sa*Sc*(1.0-Da));
+            break;
+          }
+          case OverCompositeOp:
+          case SrcOverCompositeOp:
+          {
+            pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
+            break;
+          }
+          case OverlayCompositeOp:
+          {
+            if ((2.0*Dca) < Da)
+              {
+                pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
+                  (1.0-Da));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
+              Sca*(1.0-Da));
+            break;
+          }
+          case PegtopLightCompositeOp:
+          {
+            /*
+              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)
+              {
+                pixel=QuantumRange*gamma*(Sca);
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
+              Da)+Dca*(1.0-Sa));
+            break;
+          }
+          case PinLightCompositeOp:
+          {
+            /*
+              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))
+              {
+                pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
+            break;
+          }
+          case PlusCompositeOp:
+          {
+            pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
+            break;
+          }
+          case SaturateCompositeOp:
+          {
+            if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
+              {
+                pixel=Dc;
+                break;
+              }
+            if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
+              {
+                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 ScreenCompositeOp:
+          {
+            /*
+              Screen:  a negated multiply:
+
+                f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
+            */
+            pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
+            break;
+          }
+          case SoftLightCompositeOp:
+          {
+            /*
+              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 ThresholdCompositeOp:
+          {
+            MagickRealType
+              delta;
+
+            delta=Sc-Dc;
+            if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
+              {
+                pixel=gamma*Dc;
+                break;
+              }
+            pixel=gamma*(Dc+delta*amount);
+            break;
+          }
+          case VividLightCompositeOp:
+          {
+            /*
+              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)
+              {
+                pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
+                  (1.0-Da)+Dca*(1.0-Sa));
+                break;
+              }
+            pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
+              Dca*(1.0-Sa));
+            break;
+          }
+          case XorCompositeOp:
+          {
+            pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
+            break;
+          }
+          default:
+          {
+            pixel=Sc;
+            break;
+          }
         }
-      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);
-      p+=GetPixelComponents(composite_image);
-      if (p >= (pixels+composite_image->columns*GetPixelComponents(composite_image)))
+        q[i]=ClampToQuantum(pixel);
+      }
+      p+=GetPixelChannels(composite_image);
+      channels=GetPixelChannels(composite_image);
+      if (p >= (pixels+channels*composite_image->columns))
         p=pixels;
-      q+=GetPixelComponents(image);
+      q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
       status=MagickFalse;
@@ -2706,7 +2283,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,progress++,
           image->rows);
@@ -2737,16 +2314,18 @@ MagickExport MagickBooleanType CompositeImage(Image *image,
 %
 %  The format of the TextureImage method is:
 %
-%      MagickBooleanType TextureImage(Image *image,const Image *texture)
+%      MagickBooleanType TextureImage(Image *image,const Image *texture,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o texture: This image is the texture to layer on the background.
+%    o texture_image: This image is the texture to layer on the background.
 %
 */
-MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture)
+MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
+  ExceptionInfo *exception)
 {
 #define TextureImageTag  "Texture/Image"
 
@@ -2754,8 +2333,8 @@ MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture)
     *image_view,
     *texture_view;
 
-  ExceptionInfo
-    *exception;
+  Image
+    *texture_image;
 
   MagickBooleanType
     status;
@@ -2769,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) == MagickFalse)
+  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);
+          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;
@@ -2809,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);
@@ -2819,17 +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;
-  exception=(&image->exception);
-  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++)
   {
@@ -2851,35 +2435,54 @@ 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+=GetPixelComponents(texture);
-        q+=GetPixelComponents(image);
+        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);
       }
     }
     sync=SyncCacheViewAuthenticPixels(image_view,exception);
@@ -2901,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);
 }