]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/gem.c
(no commit message)
[imagemagick] / MagickCore / gem.c
index f33a735677360ea44726866ad98415ef8240055d..440e2b1491d7c37117f7079ad41b5e3e810a15da 100644 (file)
@@ -17,7 +17,7 @@
 %                                 August 1996                                 %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2013 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  %
@@ -50,6 +50,7 @@
 #include "MagickCore/log.h"
 #include "MagickCore/memory_.h"
 #include "MagickCore/pixel-accessor.h"
+#include "MagickCore/pixel-private.h"
 #include "MagickCore/quantum.h"
 #include "MagickCore/quantum-private.h"
 #include "MagickCore/random_.h"
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   C o n v e r t H C L T o R G B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHCLToRGB() transforms a (hue, chroma, luma) to a (red, green,
+%  blue) triple.
+%
+%  The format of the ConvertHCLToRGBImage method is:
+%
+%      void ConvertHCLToRGB(const double hue,const double chroma,
+%        const double luma,double *red,double *green,double *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, chroma, luma: A double value representing a component of the
+%      HCL color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickPrivate void ConvertHCLToRGB(const double hue,const double chroma,
+  const double luma,double *red,double *green,double *blue)
+{
+  double
+    b,
+    c,
+    g,
+    h,
+    m,
+    r,
+    x;
+
+  /*
+    Convert HCL to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  h=6.0*hue;
+  c=chroma;
+  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
+  r=0.0;
+  g=0.0;
+  b=0.0;
+  if ((0.0 <= h) && (h < 1.0))
+    {
+      r=c;
+      g=x;
+    }
+  else
+    if ((1.0 <= h) && (h < 2.0))
+      {
+        r=x;
+        g=c;
+      }
+    else
+      if ((2.0 <= h) && (h < 3.0))
+        {
+          g=c;
+          b=x;
+        }
+      else
+        if ((3.0 <= h) && (h < 4.0))
+          {
+            g=x;
+            b=c;
+          }
+        else
+          if ((4.0 <= h) && (h < 5.0))
+            {
+              r=x;
+              b=c;
+            }
+          else
+            if ((5.0 <= h) && (h < 6.0))
+              {
+                r=c;
+                b=x;
+              }
+  m=luma-(0.298839*r+0.586811*g+0.114350*b);
+  *red=QuantumRange*(r+m);
+  *green=QuantumRange*(g+m);
+  *blue=QuantumRange*(b+m);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t H C L p T o R G B                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHCLpToRGB() transforms a (hue, chroma, luma) to a (red, green,
+%  blue) triple.  Since HCL colorspace is wider than RGB, we instead choose a
+%  saturation strategy to project it on the RGB cube.
+%
+%  The format of the ConvertHCLpToRGBImage method is:
+%
+%      void ConvertHCLpToRGB(const double hue,const double chroma,
+%        const double luma,double *red,double *green,double *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, chroma, luma: A double value representing a componenet of the
+%      HCLp color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickPrivate void ConvertHCLpToRGB(const double hue,const double chroma,
+  const double luma,double *red,double *green,double *blue)
+{
+  double
+    b,
+    c,
+    g,
+    h,
+    m,
+    r,
+    x,
+    z;
+
+  /*
+    Convert HCLp to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  h=6.0*hue;
+  c=chroma;
+  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
+  r=0.0;
+  g=0.0;
+  b=0.0;
+  if ((0.0 <= h) && (h < 1.0))
+    {
+      r=c;
+      g=x;
+    }
+  else
+    if ((1.0 <= h) && (h < 2.0))
+      {
+        r=x;
+        g=c;
+      }
+    else
+      if ((2.0 <= h) && (h < 3.0))
+        {
+          g=c;
+          b=x;
+        }
+      else
+        if ((3.0 <= h) && (h < 4.0))
+          {
+            g=x;
+            b=c;
+          }
+        else
+          if ((4.0 <= h) && (h < 5.0))
+            {
+              r=x;
+              b=c;
+            }
+          else
+            if ((5.0 <= h) && (h < 6.0))
+              {
+                r=c;
+                b=x;
+              }
+  m=luma-(0.298839*r+0.586811*g+0.114350*b);
+  z=1.0;
+  if (m < 0.0)
+    {
+      z=luma/(luma-m);
+      m=0.0;
+    }
+  else
+    if (m+c > 1.0)
+      {
+        z=(1.0-luma)/(m+c-luma);
+        m=1.0-z*c;
+      }
+  *red=QuantumRange*(z*r+m);
+  *green=QuantumRange*(z*g+m);
+  *blue=QuantumRange*(z*b+m);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   C o n v e r t H S B T o R G B                                             %
 %                                                                             %
 %                                                                             %
 MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
   const double brightness,double *red,double *green,double *blue)
 {
-  MagickRealType
+  double
     f,
     h,
     p,
@@ -102,7 +301,7 @@ MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
   assert(blue != (double *) NULL);
   if (saturation == 0.0)
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *red=QuantumRange*brightness;
       *green=(*red);
       *blue=(*red);
       return;
@@ -117,44 +316,44 @@ MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
     case 0:
     default:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*t);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
+      *red=QuantumRange*brightness;
+      *green=QuantumRange*t;
+      *blue=QuantumRange*p;
       break;
     }
     case 1:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*q);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*p);
+      *red=QuantumRange*q;
+      *green=QuantumRange*brightness;
+      *blue=QuantumRange*p;
       break;
     }
     case 2:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*p);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*brightness);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*t);
+      *red=QuantumRange*p;
+      *green=QuantumRange*brightness;
+      *blue=QuantumRange*t;
       break;
     }
     case 3:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*p);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*q);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *red=QuantumRange*p;
+      *green=QuantumRange*q;
+      *blue=QuantumRange*brightness;
       break;
     }
     case 4:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*t);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*p);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*brightness);
+      *red=QuantumRange*t;
+      *green=QuantumRange*p;
+      *blue=QuantumRange*brightness;
       break;
     }
     case 5:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*brightness);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*p);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*q);
+      *red=QuantumRange*brightness;
+      *green=QuantumRange*p;
+      *blue=QuantumRange*q;
       break;
     }
   }
@@ -165,6 +364,79 @@ MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   C o n v e r t H S I T o R G B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHSIToRGB() transforms a (hue, saturation, intensity) to a (red,
+%  green, blue) triple.
+%
+%  The format of the ConvertHSIToRGBImage method is:
+%
+%      void ConvertHSIToRGB(const double hue,const double saturation,
+%        const double intensity,double *red,double *green,double *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, saturation, intensity: A double value representing a
+%      component of the HSI color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickPrivate void ConvertHSIToRGB(const double hue,const double saturation,
+  const double intensity,double *red,double *green,double *blue)
+{
+  double
+    b,
+    g,
+    h,
+    r;
+
+  /*
+    Convert HSI to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  h=360.0*hue;
+  h-=360.0*floor(h/360.0);
+  if (h < 120.0)
+    {
+      b=intensity*(1.0-saturation);
+      r=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
+        (MagickPI/180.0)));
+      g=3.0*intensity-r-b;
+    }
+  else
+    if (h < 240.0)
+      {
+        h-=120.0;
+        r=intensity*(1.0-saturation);
+        g=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
+          (MagickPI/180.0)));
+        b=3.0*intensity-r-g;
+      }
+    else
+      {
+        h-=240.0;
+        g=intensity*(1.0-saturation);
+        b=intensity*(1.0+saturation*cos(h*(MagickPI/180.0))/cos((60.0-h)*
+          (MagickPI/180.0)));
+        r=3.0*intensity-g-b;
+      }
+  *red=QuantumRange*r;
+  *green=QuantumRange*g;
+  *blue=QuantumRange*b;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   C o n v e r t H S L T o R G B                                             %
 %                                                                             %
 %                                                                             %
@@ -187,32 +459,14 @@ MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
 %    o red, green, blue: A pointer to a pixel component of type Quantum.
 %
 */
-
-static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
-  MagickRealType m2,MagickRealType hue)
-{
-  if (hue < 0.0)
-    hue+=1.0;
-  if (hue > 1.0)
-    hue-=1.0;
-  if ((6.0*hue) < 1.0)
-    return(m1+6.0*(m2-m1)*hue);
-  if ((2.0*hue) < 1.0)
-    return(m2);
-  if ((3.0*hue) < 2.0)
-    return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
-  return(m1);
-}
-
 MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
   const double lightness,double *red,double *green,double *blue)
 {
-  MagickRealType
-    b,
-    g,
-    r,
-    m1,
-    m2;
+  double
+    c,
+    h,
+    min,
+    x;
 
   /*
     Convert HSL to RGB colorspace.
@@ -220,24 +474,167 @@ MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
   assert(red != (double *) NULL);
   assert(green != (double *) NULL);
   assert(blue != (double *) NULL);
-  if (saturation == 0)
+  h=hue*360.0;
+  if (lightness <= 0.5)
+    c=2.0*lightness*saturation;
+  else
+    c=(2.0-2.0*lightness)*saturation;
+  min=lightness-0.5*c;
+  h-=360.0*floor(h/360.0);
+  h/=60.0;
+  x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
+  switch ((int) floor(h))
+  {
+    case 0:
     {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*lightness);
-      *green=(*red);
-      *blue=(*red);
-      return;
+      *red=QuantumRange*(min+c);
+      *green=QuantumRange*(min+x);
+      *blue=QuantumRange*min;
+      break;
     }
-  if (lightness < 0.5)
-    m2=lightness*(saturation+1.0);
-  else
-    m2=(lightness+saturation)-(lightness*saturation);
-  m1=2.0*lightness-m2;
-  r=ConvertHueToRGB(m1,m2,hue+1.0/3.0);
-  g=ConvertHueToRGB(m1,m2,hue);
-  b=ConvertHueToRGB(m1,m2,hue-1.0/3.0);
-  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
-  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
-  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
+    case 1:
+    {
+      *red=QuantumRange*(min+x);
+      *green=QuantumRange*(min+c);
+      *blue=QuantumRange*min;
+      break;
+    }
+    case 2:
+    {
+      *red=QuantumRange*min;
+      *green=QuantumRange*(min+c);
+      *blue=QuantumRange*(min+x);
+      break;
+    }
+    case 3:
+    {
+      *red=QuantumRange*min;
+      *green=QuantumRange*(min+x);
+      *blue=QuantumRange*(min+c);
+      break;
+    }
+    case 4:
+    {
+      *red=QuantumRange*(min+x);
+      *green=QuantumRange*min;
+      *blue=QuantumRange*(min+c);
+      break;
+    }
+    case 5:
+    {
+      *red=QuantumRange*(min+c);
+      *green=QuantumRange*min;
+      *blue=QuantumRange*(min+x);
+      break;
+    }
+    default:
+    {
+      *red=0.0;
+      *green=0.0;
+      *blue=0.0;
+    }
+  }
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t H S V T o R G B                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertHSVToRGB() transforms a (hue, saturation, value) to a (red,
+%  green, blue) triple.
+%
+%  The format of the ConvertHSVToRGBImage method is:
+%
+%      void ConvertHSVToRGB(const double hue,const double saturation,
+%        const double value,double *red,double *green,double *blue)
+%
+%  A description of each parameter follows:
+%
+%    o hue, saturation, value: A double value representing a
+%      component of the HSV color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickPrivate void ConvertHSVToRGB(const double hue,const double saturation,
+  const double value,double *red,double *green,double *blue)
+{
+  double
+    c,
+    h,
+    min,
+    x;
+
+  /*
+    Convert HSV to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  h=hue*360.0;
+  c=value*saturation;
+  min=value-c;
+  h-=360.0*floor(h/360.0);
+  h/=60.0;
+  x=c*(1.0-fabs(h-2.0*floor(h/2.0)-1.0));
+  switch ((int) floor(h))
+  {
+    case 0:
+    {
+      *red=QuantumRange*(min+c);
+      *green=QuantumRange*(min+x);
+      *blue=QuantumRange*min;
+      break;
+    }
+    case 1:
+    {
+      *red=QuantumRange*(min+x);
+      *green=QuantumRange*(min+c);
+      *blue=QuantumRange*min;
+      break;
+    }
+    case 2:
+    {
+      *red=QuantumRange*min;
+      *green=QuantumRange*(min+c);
+      *blue=QuantumRange*(min+x);
+      break;
+    }
+    case 3:
+    {
+      *red=QuantumRange*min;
+      *green=QuantumRange*(min+x);
+      *blue=QuantumRange*(min+c);
+      break;
+    }
+    case 4:
+    {
+      *red=QuantumRange*(min+x);
+      *green=QuantumRange*min;
+      *blue=QuantumRange*(min+c);
+      break;
+    }
+    case 5:
+    {
+      *red=QuantumRange*(min+c);
+      *green=QuantumRange*min;
+      *blue=QuantumRange*(min+x);
+      break;
+    }
+    default:
+    {
+      *red=0.0;
+      *green=0.0;
+      *blue=0.0;
+    }
+  }
 }
 \f
 /*
@@ -264,56 +661,311 @@ MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
 %    o hue, whiteness, blackness: A double value representing a
 %      component of the HWB color space.
 %
-%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
+  const double blackness,double *red,double *green,double *blue)
+{
+  double
+    b,
+    f,
+    g,
+    n,
+    r,
+    v;
+
+  register ssize_t
+    i;
+
+  /*
+    Convert HWB to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  v=1.0-blackness;
+  if (hue == -1.0)
+    {
+      *red=QuantumRange*v;
+      *green=QuantumRange*v;
+      *blue=QuantumRange*v;
+      return;
+    }
+  i=(ssize_t) floor(6.0*hue);
+  f=6.0*hue-i;
+  if ((i & 0x01) != 0)
+    f=1.0-f;
+  n=whiteness+f*(v-whiteness);  /* linear interpolation */
+  switch (i)
+  {
+    default:
+    case 6:
+    case 0: r=v; g=n; b=whiteness; break;
+    case 1: r=n; g=v; b=whiteness; break;
+    case 2: r=whiteness; g=v; b=n; break;
+    case 3: r=whiteness; g=n; b=v; break;
+    case 4: r=n; g=whiteness; b=v; break;
+    case 5: r=v; g=whiteness; b=n; break;
+  }
+  *red=QuantumRange*r;
+  *green=QuantumRange*g;
+  *blue=QuantumRange*b;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t L C H a b T o R G B                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertLCHabToRGB() transforms a (luma, chroma, hue) to a (red, green,
+%  blue) triple.
+%
+%  The format of the ConvertLCHabToRGBImage method is:
+%
+%      void ConvertLCHabToRGB(const double luma,const double chroma,
+%        const double hue,double *red,double *green,double *blue)
+%
+%  A description of each parameter follows:
+%
+%    o luma, chroma, hue: A double value representing a component of the
+%      LCHab color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+
+static inline void ConvertLCHabToXYZ(const double luma,const double chroma,
+  const double hue,double *X,double *Y,double *Z)
+{
+  ConvertLabToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
+    sin(hue*MagickPI/180.0),X,Y,Z);
+}
+
+MagickPrivate void ConvertLCHabToRGB(const double luma,const double chroma,
+  const double hue,double *red,double *green,double *blue)
+{
+  double
+    X,
+    Y,
+    Z;
+
+  /*
+    Convert LCHab to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  ConvertLCHabToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*(hue-0.5),&X,&Y,&Z);
+  ConvertXYZToRGB(X,Y,Z,red,green,blue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t L C H u v T o R G B                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertLCHuvToRGB() transforms a (luma, chroma, hue) to a (red, green,
+%  blue) triple.
+%
+%  The format of the ConvertLCHuvToRGBImage method is:
+%
+%      void ConvertLCHuvToRGB(const double luma,const double chroma,
+%        const double hue,double *red,double *green,double *blue)
+%
+%  A description of each parameter follows:
+%
+%    o luma, chroma, hue: A double value representing a component of the
+%      LCHuv color space.
+%
+%    o red, green, blue: A pointer to a pixel component of type Quantum.
+%
+*/
+
+static inline void ConvertLCHuvToXYZ(const double luma,const double chroma,
+  const double hue,double *X,double *Y,double *Z)
+{
+  ConvertLuvToXYZ(luma,chroma*cos(hue*MagickPI/180.0),chroma*
+    sin(hue*MagickPI/180.0),X,Y,Z);
+}
+
+MagickPrivate void ConvertLCHuvToRGB(const double luma,const double chroma,
+  const double hue,double *red,double *green,double *blue)
+{
+  double
+    X,
+    Y,
+    Z;
+
+  /*
+    Convert LCHuv to RGB colorspace.
+  */
+  assert(red != (double *) NULL);
+  assert(green != (double *) NULL);
+  assert(blue != (double *) NULL);
+  ConvertLCHuvToXYZ(100.0*luma,255.0*(chroma-0.5),360.0*(hue-0.5),&X,&Y,&Z)
+  ConvertXYZToRGB(X,Y,Z,red,green,blue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o H C L                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHCL() transforms a (red, green, blue) to a (hue, chroma,
+%  luma) triple.
+%
+%  The format of the ConvertRGBToHCL method is:
+%
+%      void ConvertRGBToHCL(const double red,const double green,
+%        const double blue,double *hue,double *chroma,double *luma)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel.
+%
+%    o hue, chroma, luma: A pointer to a double value representing a
+%      component of the HCL color space.
+%
+*/
+
+static inline double MagickMax(const double x,const double y)
+{
+  if (x > y)
+    return(x);
+  return(y);
+}
+
+static inline double MagickMin(const double x,const double y)
+{
+  if (x < y)
+    return(x);
+  return(y);
+}
+
+MagickPrivate void ConvertRGBToHCL(const double red,const double green,
+  const double blue,double *hue,double *chroma,double *luma)
+{
+  double
+    b,
+    c,
+    g,
+    h,
+    max,
+    r;
+
+  /*
+    Convert RGB to HCL colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(chroma != (double *) NULL);
+  assert(luma != (double *) NULL);
+  r=red;
+  g=green;
+  b=blue;
+  max=MagickMax(r,MagickMax(g,b));
+  c=max-(double) MagickMin(r,MagickMin(g,b));
+  h=0.0;
+  if (c == 0.0)
+    h=0.0;
+  else
+    if (red == max)
+      h=fmod((g-b)/c+6.0,6.0);
+    else
+      if (green == max)
+        h=((b-r)/c)+2.0;
+      else
+        if (blue == max)
+          h=((r-g)/c)+4.0;
+  *hue=(h/6.0);
+  *chroma=QuantumScale*c;
+  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o H C L p                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHCLp() transforms a (red, green, blue) to a (hue, chroma,
+%  luma) triple.
+%
+%  The format of the ConvertRGBToHCLp method is:
+%
+%      void ConvertRGBToHCLp(const double red,const double green,
+%        const double blue,double *hue,double *chroma,double *luma)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel.
+%
+%    o hue, chroma, luma: A pointer to a double value representing a
+%      component of the HCL color space.
 %
 */
-MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
-  const double blackness,double *red,double *green,double *blue)
+MagickPrivate void ConvertRGBToHCLp(const double red,const double green,
+  const double blue,double *hue,double *chroma,double *luma)
 {
-  MagickRealType
+  double
     b,
-    f,
+    c,
     g,
-    n,
-    r,
-    v;
-
-  register ssize_t
-    i;
+    h,
+    max,
+    r;
 
   /*
-    Convert HWB to RGB colorspace.
+    Convert RGB to HCL colorspace.
   */
-  assert(red != (double *) NULL);
-  assert(green != (double *) NULL);
-  assert(blue != (double *) NULL);
-  v=1.0-blackness;
-  if (hue == 0.0)
-    {
-      *red=ClampToQuantum((MagickRealType) QuantumRange*v);
-      *green=ClampToQuantum((MagickRealType) QuantumRange*v);
-      *blue=ClampToQuantum((MagickRealType) QuantumRange*v);
-      return;
-    }
-  i=(ssize_t) floor(6.0*hue);
-  f=6.0*hue-i;
-  if ((i & 0x01) != 0)
-    f=1.0-f;
-  n=whiteness+f*(v-whiteness);  /* linear interpolation */
-  switch (i)
-  {
-    default:
-    case 6:
-    case 0: r=v; g=n; b=whiteness; break;
-    case 1: r=n; g=v; b=whiteness; break;
-    case 2: r=whiteness; g=v; b=n; break;
-    case 3: r=whiteness; g=n; b=v; break;
-    case 4: r=n; g=whiteness; b=v; break;
-    case 5: r=v; g=whiteness; b=n; break;
-  }
-  *red=ClampToQuantum((MagickRealType) QuantumRange*r);
-  *green=ClampToQuantum((MagickRealType) QuantumRange*g);
-  *blue=ClampToQuantum((MagickRealType) QuantumRange*b);
+  assert(hue != (double *) NULL);
+  assert(chroma != (double *) NULL);
+  assert(luma != (double *) NULL);
+  r=red;
+  g=green;
+  b=blue;
+  max=MagickMax(r,MagickMax(g,b));
+  c=max-(double) MagickMin(r,MagickMin(g,b));
+  h=0.0;
+  if (c == 0.0)
+    h=0.0;
+  else
+    if (red == max)
+      h=fmod((g-b)/c+6.0,6.0);
+    else
+      if (green == max)
+        h=((b-r)/c)+2.0;
+      else
+        if (blue == max)
+          h=((r-g)/c)+4.0;
+  *hue=(h/6.0);
+  *chroma=QuantumScale*c;
+  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
 }
 \f
 /*
@@ -347,10 +999,13 @@ MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
 MagickPrivate void ConvertRGBToHSB(const double red,const double green,
   const double blue,double *hue,double *saturation,double *brightness)
 {
-  MagickRealType
+  double
+    b,
     delta,
+    g,
     max,
-    min;
+    min,
+    r;
 
   /*
     Convert RGB to HSB colorspace.
@@ -361,26 +1016,29 @@ MagickPrivate void ConvertRGBToHSB(const double red,const double green,
   *hue=0.0;
   *saturation=0.0;
   *brightness=0.0;
-  min=(MagickRealType) (red < green ? red : green);
-  if ((MagickRealType) blue < min)
-    min=(MagickRealType) blue;
-  max=(MagickRealType) (red > green ? red : green);
-  if ((MagickRealType) blue > max)
-    max=(MagickRealType) blue;
+  r=red;
+  g=green;
+  b=blue;
+  min=r < g ? r : g;
+  if (b < min)
+    min=b;
+  max=r > g ? r : g;
+  if (b > max)
+    max=b;
   if (max == 0.0)
     return;
   delta=max-min;
-  *saturation=(double) (delta/max);
-  *brightness=(double) (QuantumScale*max);
+  *saturation=delta/max;
+  *brightness=QuantumScale*max;
   if (delta == 0.0)
     return;
-  if ((MagickRealType) red == max)
-    *hue=(double) ((green-(MagickRealType) blue)/delta);
+  if (r == max)
+    *hue=(g-b)/delta;
   else
-    if ((MagickRealType) green == max)
-      *hue=(double) (2.0+(blue-(MagickRealType) red)/delta);
+    if (g == max)
+      *hue=2.0+(b-r)/delta;
     else
-      *hue=(double) (4.0+(red-(MagickRealType) green)/delta);
+      *hue=4.0+(r-g)/delta;
   *hue/=6.0;
   if (*hue < 0.0)
     *hue+=1.0;
@@ -391,6 +1049,63 @@ MagickPrivate void ConvertRGBToHSB(const double red,const double green,
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   C o n v e r t R G B T o H S I                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHSI() transforms a (red, green, blue) to a (hue, saturation,
+%  intensity) triple.
+%
+%  The format of the ConvertRGBToHSI method is:
+%
+%      void ConvertRGBToHSI(const double red,const double green,
+%        const double blue,double *hue,double *saturation,double *intensity)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel..
+%
+%    o hue, saturation, intensity: A pointer to a double value representing a
+%      component of the HSI color space.
+%
+*/
+MagickPrivate void ConvertRGBToHSI(const double red,const double green,
+  const double blue,double *hue,double *saturation,double *intensity)
+{
+  double
+    alpha,
+    beta;
+
+  /*
+    Convert RGB to HSI colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(saturation != (double *) NULL);
+  assert(intensity != (double *) NULL);
+  *intensity=(QuantumScale*red+QuantumScale*green+QuantumScale*blue)/3.0;
+  if (*intensity <= 0.0)
+    {
+      *hue=0.0;
+      *saturation=0.0;
+      return;
+    }
+  *saturation=1.0-MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
+    QuantumScale*blue))/(*intensity);
+  alpha=0.5*(2.0*QuantumScale*red-QuantumScale*green-QuantumScale*blue);
+  beta=0.8660254037844385*(QuantumScale*green-QuantumScale*blue);
+  *hue=atan2(beta,alpha)*(180.0/MagickPI)/360.0;
+  if (*hue < 0.0)
+    *hue+=1.0;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   C o n v e r t R G B T o H S L                                             %
 %                                                                             %
 %                                                                             %
@@ -414,31 +1129,13 @@ MagickPrivate void ConvertRGBToHSB(const double red,const double green,
 %      component of the HSL color space.
 %
 */
-
-static inline double MagickMax(const double x,const double y)
-{
-  if (x > y)
-    return(x);
-  return(y);
-}
-
-static inline double MagickMin(const double x,const double y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-
 MagickExport void ConvertRGBToHSL(const double red,const double green,
   const double blue,double *hue,double *saturation,double *lightness)
 {
-  MagickRealType
-    b,
-    delta,
-    g,
+  double
+    c,
     max,
-    min,
-    r;
+    min;
 
   /*
     Convert RGB to HSL colorspace.
@@ -446,37 +1143,103 @@ MagickExport void ConvertRGBToHSL(const double red,const double green,
   assert(hue != (double *) NULL);
   assert(saturation != (double *) NULL);
   assert(lightness != (double *) NULL);
-  r=QuantumScale*red;
-  g=QuantumScale*green;
-  b=QuantumScale*blue;
-  max=MagickMax(r,MagickMax(g,b));
-  min=MagickMin(r,MagickMin(g,b));
-  *lightness=(double) ((min+max)/2.0);
-  delta=max-min;
-  if (delta == 0.0)
+  max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
+    QuantumScale*blue));
+  min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
+    QuantumScale*blue));
+  c=max-min;
+  *lightness=(max+min)/2.0;
+  if (c <= 0.0)
     {
       *hue=0.0;
       *saturation=0.0;
       return;
     }
-  if (*lightness < 0.5)
-    *saturation=(double) (delta/(min+max));
+  if (max == (QuantumScale*red))
+    {
+      *hue=(QuantumScale*green-QuantumScale*blue)/c;
+      if ((QuantumScale*green) < (QuantumScale*blue))
+        *hue+=6.0;
+    }
   else
-    *saturation=(double) (delta/(2.0-max-min));
-  if (r == max)
-    *hue=((((max-b)/6.0)+(delta/2.0))-(((max-g)/6.0)+(delta/2.0)))/delta;
+    if (max == (QuantumScale*green))
+      *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
+    else
+      *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
+  *hue*=60.0/360.0;
+  if (*lightness <= 0.5)
+    *saturation=c/(2.0*(*lightness));
   else
-    if (g == max)
-      *hue=(1.0/3.0)+((((max-r)/6.0)+(delta/2.0))-(((max-b)/6.0)+(delta/2.0)))/
-        delta;
+    *saturation=c/(2.0-2.0*(*lightness));
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o H S V                                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToHSV() transforms a (red, green, blue) to a (hue, saturation,
+%  value) triple.
+%
+%  The format of the ConvertRGBToHSV method is:
+%
+%      void ConvertRGBToHSV(const double red,const double green,
+%        const double blue,double *hue,double *saturation,double *value)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel..
+%
+%    o hue, saturation, value: A pointer to a double value representing a
+%      component of the HSV color space.
+%
+*/
+MagickPrivate void ConvertRGBToHSV(const double red,const double green,
+  const double blue,double *hue,double *saturation,double *value)
+{
+  double
+    c,
+    max,
+    min;
+
+  /*
+    Convert RGB to HSV colorspace.
+  */
+  assert(hue != (double *) NULL);
+  assert(saturation != (double *) NULL);
+  assert(value != (double *) NULL);
+  max=MagickMax(QuantumScale*red,MagickMax(QuantumScale*green,
+    QuantumScale*blue));
+  min=MagickMin(QuantumScale*red,MagickMin(QuantumScale*green,
+    QuantumScale*blue));
+  c=max-min;
+  *value=max;
+  if (c <= 0.0)
+    {
+      *hue=0.0;
+      *saturation=0.0;
+      return;
+    }
+  if (max == (QuantumScale*red))
+    {
+      *hue=(QuantumScale*green-QuantumScale*blue)/c;
+      if ((QuantumScale*green) < (QuantumScale*blue))
+        *hue+=6.0;
+    }
+  else
+    if (max == (QuantumScale*green))
+      *hue=2.0+(QuantumScale*blue-QuantumScale*red)/c;
     else
-      if (b == max)
-        *hue=(2.0/3.0)+((((max-g)/6.0)+(delta/2.0))-(((max-r)/6.0)+
-          (delta/2.0)))/delta;
-  if (*hue < 0.0)
-    *hue+=1.0;
-  if (*hue > 1.0)
-    *hue-=1.0;
+      *hue=4.0+(QuantumScale*red-QuantumScale*green)/c;
+  *hue*=60.0/360.0;
+  *saturation=c/max;
 }
 \f
 /*
@@ -510,11 +1273,12 @@ MagickExport void ConvertRGBToHSL(const double red,const double green,
 MagickPrivate void ConvertRGBToHWB(const double red,const double green,
   const double blue,double *hue,double *whiteness,double *blackness)
 {
-  long
-    i;
-
-  MagickRealType
+  double
+    b,
     f,
+    g,
+    p,
+    r,
     v,
     w;
 
@@ -524,22 +1288,143 @@ MagickPrivate void ConvertRGBToHWB(const double red,const double green,
   assert(hue != (double *) NULL);
   assert(whiteness != (double *) NULL);
   assert(blackness != (double *) NULL);
-  w=(MagickRealType) MagickMin((double) red,MagickMin((double) green,(double)
-    blue));
-  v=(MagickRealType) MagickMax((double) red,MagickMax((double) green,(double)
-    blue));
+  r=red;
+  g=green;
+  b=blue;
+  w=MagickMin(r,MagickMin(g,b));
+  v=MagickMax(r,MagickMax(g,b));
   *blackness=1.0-QuantumScale*v;
   *whiteness=QuantumScale*w;
   if (v == w)
     {
-      *hue=0.0;
+      *hue=(-1.0);
       return;
     }
-  f=((MagickRealType) red == w) ? green-(MagickRealType) blue :
-    (((MagickRealType) green == w) ? blue-(MagickRealType) red : red-
-    (MagickRealType) green);
-  i=((MagickRealType) red == w) ? 3 : (((MagickRealType) green == w) ? 5 : 1);
-  *hue=((double) i-f/(v-1.0*w))/6.0;
+  f=(r == w) ? g-b : ((g == w) ? b-r : r-g);
+  p=(r == w) ? 3.0 : ((g == w) ? 5.0 : 1.0);
+  *hue=(p-f/(v-1.0*w))/6.0;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o L C H a b                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToLCHab() transforms a (red, green, blue) to a (luma, chroma,
+%  hue) triple.
+%
+%  The format of the ConvertRGBToLCHab method is:
+%
+%      void ConvertRGBToLCHab(const double red,const double green,
+%        const double blue,double *luma,double *chroma,double *hue)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel.
+%
+%    o luma, chroma, hue: A pointer to a double value representing a
+%      component of the LCH color space.
+%
+*/
+
+static inline void ConvertXYZToLCHab(const double X,const double Y,
+  const double Z,double *luma,double *chroma,double *hue)
+{
+  double
+    a,
+    b;
+
+  ConvertXYZToLab(X,Y,Z,luma,&a,&b);
+  *chroma=hypot(255.0*(a-0.5),255.0*(b-0.5))/255.0+0.5;
+  *hue=180.0*atan2(255.0*(b-0.5),255.0*(a-0.5))/MagickPI/360.0+0.5;
+  if (*hue < 0.0)
+    *hue+=1.0;
+}
+
+MagickPrivate void ConvertRGBToLCHab(const double red,const double green,
+  const double blue,double *luma,double *chroma,double *hue)
+{
+  double
+    X,
+    Y,
+    Z;
+
+  /*
+    Convert RGB to LCHab colorspace.
+  */
+  assert(luma != (double *) NULL);
+  assert(chroma != (double *) NULL);
+  assert(hue != (double *) NULL);
+  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
+  ConvertXYZToLCHab(X,Y,Z,luma,chroma,hue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   C o n v e r t R G B T o L C H u v                                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ConvertRGBToLCHuv() transforms a (red, green, blue) to a (luma, chroma,
+%  hue) triple.
+%
+%  The format of the ConvertRGBToLCHuv method is:
+%
+%      void ConvertRGBToLCHuv(const double red,const double green,
+%        const double blue,double *luma,double *chroma,double *hue)
+%
+%  A description of each parameter follows:
+%
+%    o red, green, blue: A Quantum value representing the red, green, and
+%      blue component of a pixel.
+%
+%    o luma, chroma, hue: A pointer to a double value representing a
+%      component of the LCHuv color space.
+%
+*/
+
+static inline void ConvertXYZToLCHuv(const double X,const double Y,
+  const double Z,double *luma,double *chroma,double *hue)
+{
+  double
+    u,
+    v;
+
+  ConvertXYZToLuv(X,Y,Z,luma,&u,&v);
+  *chroma=hypot(354.0*u-134.0,262.0*v-140.0)/255.0+0.5;
+  *hue=180.0*atan2(262.0*v-140.0,354.0*u-134.0)/MagickPI/360.0+0.5;
+  if (*hue < 0.0)
+    *hue+=1.0;
+}
+
+MagickPrivate void ConvertRGBToLCHuv(const double red,const double green,
+  const double blue,double *luma,double *chroma,double *hue)
+{
+  double
+    X,
+    Y,
+    Z;
+
+  /*
+    Convert RGB to LCHuv colorspace.
+  */
+  assert(luma != (double *) NULL);
+  assert(chroma != (double *) NULL);
+  assert(hue != (double *) NULL);
+  ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
+  ConvertXYZToLCHuv(X,Y,Z,luma,chroma,hue);
 }
 \f
 /*
@@ -564,7 +1449,7 @@ MagickPrivate void ConvertRGBToHWB(const double red,const double green,
 %
 %  A description of each parameter follows:
 %
-%    o expansion: Method ExpandAffine returns the affine's expansion factor.
+%    o expansion: ExpandAffine returns the affine's expansion factor.
 %
 %    o affine: A pointer the affine transform of type AffineMatrix.
 %
@@ -591,8 +1476,7 @@ MagickExport double ExpandAffine(const AffineMatrix *affine)
 %  The format of the GenerateDifferentialNoise method is:
 %
 %      double GenerateDifferentialNoise(RandomInfo *random_info,
-%        const Quantum pixel,const NoiseType noise_type,
-%        const MagickRealType attenuate)
+%        const Quantum pixel,const NoiseType noise_type,const double attenuate)
 %
 %  A description of each parameter follows:
 %
@@ -606,16 +1490,16 @@ MagickExport double ExpandAffine(const AffineMatrix *affine)
 %
 */
 MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
-  const Quantum pixel,const NoiseType noise_type,const MagickRealType attenuate)
+  const Quantum pixel,const NoiseType noise_type,const double attenuate)
 {
-#define NoiseEpsilon  (attenuate*1.0e-5)
-#define SigmaUniform  (attenuate*4.0)
-#define SigmaGaussian  (attenuate*4.0)
-#define SigmaImpulse  (attenuate*0.10)
-#define SigmaLaplacian (attenuate*10.0)
-#define SigmaMultiplicativeGaussian  (attenuate*1.0)
-#define SigmaPoisson  (attenuate*0.05)
-#define TauGaussian  (attenuate*20.0)
+#define SigmaUniform  (attenuate*0.015625)
+#define SigmaGaussian  (attenuate*0.015625)
+#define SigmaImpulse  (attenuate*0.1)
+#define SigmaLaplacian (attenuate*0.0390625)
+#define SigmaMultiplicativeGaussian  (attenuate*0.5)
+#define SigmaPoisson  (attenuate*12.5)
+#define SigmaRandom  (attenuate)
+#define TauGaussian  (attenuate*0.078125)
 
   double
     alpha,
@@ -629,8 +1513,7 @@ MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
     case UniformNoise:
     default:
     {
-      noise=(double) pixel+ScaleCharToQuantum((unsigned char)
-        (SigmaUniform*(alpha)));
+      noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5));
       break;
     }
     case GaussianNoise:
@@ -645,49 +1528,47 @@ MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
       gamma=sqrt(-2.0*log(alpha));
       sigma=gamma*cos((double) (2.0*MagickPI*beta));
       tau=gamma*sin((double) (2.0*MagickPI*beta));
-      noise=(double) pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
-        TauGaussian*tau;
-      break;
-    }
-    case MultiplicativeGaussianNoise:
-    {
-      if (alpha <= NoiseEpsilon)
-        sigma=(double) QuantumRange;
-      else
-        sigma=sqrt(-2.0*log(alpha));
-      beta=GetPseudoRandomValue(random_info);
-      noise=(double) pixel+pixel*SigmaMultiplicativeGaussian*sigma/2.0*
-        cos((double) (2.0*MagickPI*beta));
+      noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
+        QuantumRange*TauGaussian*tau);
       break;
     }
     case ImpulseNoise:
     {
       if (alpha < (SigmaImpulse/2.0))
         noise=0.0;
-       else
-         if (alpha >= (1.0-(SigmaImpulse/2.0)))
-           noise=(double) QuantumRange;
-         else
-           noise=(double) pixel;
+      else
+        if (alpha >= (1.0-(SigmaImpulse/2.0)))
+          noise=(double) QuantumRange;
+        else
+          noise=(double) pixel;
       break;
     }
     case LaplacianNoise:
     {
       if (alpha <= 0.5)
         {
-          if (alpha <= NoiseEpsilon)
-            noise=(double) pixel-(double) QuantumRange;
+          if (alpha <= MagickEpsilon)
+            noise=(double) (pixel-QuantumRange);
           else
-            noise=(double) pixel+ScaleCharToQuantum((unsigned char)
-              (SigmaLaplacian*log((2.0*alpha))+0.5));
+            noise=(double) (pixel+QuantumRange*SigmaLaplacian*log(2.0*alpha)+
+              0.5);
           break;
         }
       beta=1.0-alpha;
-      if (beta <= (0.5*NoiseEpsilon))
+      if (beta <= (0.5*MagickEpsilon))
         noise=(double) (pixel+QuantumRange);
       else
-        noise=(double) pixel-ScaleCharToQuantum((unsigned char)
-          (SigmaLaplacian*log((2.0*beta))+0.5));
+        noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5);
+      break;
+    }
+    case MultiplicativeGaussianNoise:
+    {
+      sigma=1.0;
+      if (alpha > MagickEpsilon)
+        sigma=sqrt(-2.0*log(alpha));
+      beta=GetPseudoRandomValue(random_info);
+      noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma*
+        cos((double) (2.0*MagickPI*beta))/2.0);
       break;
     }
     case PoissonNoise:
@@ -698,18 +1579,18 @@ MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
       register ssize_t
         i;
 
-      poisson=exp(-SigmaPoisson*ScaleQuantumToChar(pixel));
+      poisson=exp(-SigmaPoisson*QuantumScale*pixel);
       for (i=0; alpha > poisson; i++)
       {
         beta=GetPseudoRandomValue(random_info);
         alpha*=beta;
       }
-      noise=(double) ScaleCharToQuantum((unsigned char) (i/SigmaPoisson));
+      noise=(double) (QuantumRange*i/SigmaPoisson);
       break;
     }
     case RandomNoise:
     {
-      noise=(double) QuantumRange*alpha;
+      noise=(double) (QuantumRange*SigmaRandom*alpha);
       break;
     }
   }
@@ -738,8 +1619,8 @@ MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
 %
 %  A description of each parameter follows:
 %
-%    o width: Method GetOptimalKernelWidth returns the optimal width of
-%      convolution kernel.
+%    o width: GetOptimalKernelWidth returns the optimal width of a
+%      convolution kernel.
 %
 %    o radius: the radius of the Gaussian, in pixels, not counting the center
 %      pixel.
@@ -772,12 +1653,12 @@ MagickPrivate size_t GetOptimalKernelWidth1D(const double radius,
   gamma=fabs(sigma);
   if (gamma <= MagickEpsilon)
     return(3UL);
-  alpha=1.0/(2.0*gamma*gamma);
-  beta=(double) (1.0/(MagickSQ2PI*gamma));
+  alpha=PerceptibleReciprocal(2.0*gamma*gamma);
+  beta=(double) PerceptibleReciprocal((double) MagickSQ2PI*gamma);
   for (width=5; ; )
   {
     normalize=0.0;
-    j=(ssize_t) width/2;
+    j=(ssize_t) (width-1)/2;
     for (i=(-j); i <= j; i++)
       normalize+=exp(-((double) (i*i))*alpha)*beta;
     value=exp(-((double) (j*j))*alpha)*beta/normalize;
@@ -812,12 +1693,12 @@ MagickPrivate size_t GetOptimalKernelWidth2D(const double radius,
   gamma=fabs(sigma);
   if (gamma <= MagickEpsilon)
     return(3UL);
-  alpha=1.0/(2.0*gamma*gamma);
-  beta=(double) (1.0/(Magick2PI*gamma*gamma));
+  alpha=PerceptibleReciprocal(2.0*gamma*gamma);
+  beta=(double) PerceptibleReciprocal((double) Magick2PI*gamma*gamma);
   for (width=5; ; )
   {
     normalize=0.0;
-    j=(ssize_t) width/2;
+    j=(ssize_t) (width-1)/2;
     for (v=(-j); v <= j; v++)
       for (u=(-j); u <= j; u++)
         normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;