adjustColor function

Image adjustColor (
  1. Image src,
  2. {int blacks,
  3. int whites,
  4. int mids,
  5. num contrast,
  6. num saturation,
  7. num brightness,
  8. num gamma,
  9. num exposure,
  10. num hue,
  11. num amount}
)

Adjust the color of the src image using various color transformations.

blacks defines the black level of the image, as a color.

whites defines the white level of the image, as a color.

mids defines the mid level of hte image, as a color.

contrast increases (> 1) / decreases (< 1) the contrast of the image by pushing colors away/toward neutral gray, where at 0.0 the image is entirely neutral gray (0 contrast), 1.0, the image is not adjusted and > 1.0 the image increases contrast.

saturation increases (> 1) / decreases (< 1) the saturation of the image by pushing colors away/toward their grayscale value, where 0.0 is grayscale and 1.0 is the original image, and > 1.0 the image becomes more saturated.

brightness is a constant scalar of the image colors. At 0 the image is black, 1.0 unmodified, and > 1.0 the image becomes brighter.

gamma is an exponential scalar of the image colors. At < 1.0 the image becomes brighter, and > 1.0 the image becomes darker. A gamma of 1/2.2 will convert the image colors to linear color space.

exposure is an exponential scalar of the image as rgb/// pow(2, exposure). At 0, the image is unmodified; as the exposure increases, the image brightens.

hue shifts the hue component of the image colors in degrees. A hue of 0 will have no affect, and a hue of 45 will shift the hue of all colors by 45 degrees.

amount controls how much affect this filter has on the src image, where 0.0 has no effect and 1.0 has full effect.

Implementation

Image adjustColor(Image src,
    {int blacks,
    int whites,
    int mids,
    num contrast,
    num saturation,
    num brightness,
    num gamma,
    num exposure,
    num hue,
    num amount}) {
  if (amount == 0.0) {
    return src;
  }

  contrast = contrast != null ? contrast.clamp(0, 1) : null;
  saturation = saturation != null ? saturation.clamp(0, 1) : null;
  brightness = brightness != null ? brightness.clamp(0, 1) : null;
  gamma = gamma != null ? gamma.clamp(0, 1000) : null;
  exposure = exposure != null ? exposure.clamp(0, 1000) : null;
  amount = amount != null ? amount.clamp(0, 1000) : null;

  const DEG_TO_RAD = 0.0174532925;
  const avgLumR = 0.5;
  const avgLumG = 0.5;
  const avgLumB = 0.5;
  const lumCoeffR = 0.2125;
  const lumCoeffG = 0.7154;
  const lumCoeffB = 0.0721;

  num br, bg, bb;
  num wr, wg, wb;
  num mr, mg, mb;
  if (blacks != null || whites != null || mids != null) {
    br = blacks != null ? getRed(blacks) / 255.0 : 0.0;
    bg = blacks != null ? getGreen(blacks) / 255.0 : 0.0;
    bb = blacks != null ? getBlue(blacks) / 255.0 : 0.0;

    wr = whites != null ? getRed(whites) / 255.0 : 1.0;
    wg = whites != null ? getGreen(whites) / 255.0 : 1.0;
    wb = whites != null ? getBlue(whites) / 255.0 : 1.0;

    mr = mids != null ? getRed(mids) / 255.0 : 0.5;
    mg = mids != null ? getGreen(mids) / 255.0 : 0.5;
    mb = mids != null ? getBlue(mids) / 255.0 : 0.5;

    mr = 1.0 / (1.0 + 2.0 * (mr - 0.5));
    mg = 1.0 / (1.0 + 2.0 * (mg - 0.5));
    mb = 1.0 / (1.0 + 2.0 * (mb - 0.5));
  }

  num invSaturation = saturation != null ? 1.0 - saturation.clamp(0, 1) : 0.0;
  num invContrast = contrast != null ? 1.0 - contrast.clamp(0, 1) : 0.0;

  if (exposure != null) {
    exposure = pow(2.0, exposure);
  }

  num hueR;
  num hueG;
  num hueB;
  if (hue != null) {
    hue *= DEG_TO_RAD;
    var s = sin(hue);
    var c = cos(hue);

    hueR = (2.0 * c) / 3.0;
    hueG = (-sqrt(3.0) * s - c) / 3.0;
    hueB = ((sqrt(3.0) * s - c) + 1.0) / 3.0;
  }

  var invAmount = amount != null ? 1.0 - amount.clamp(0, 1) : 0.0;

  var pixels = src.getBytes();
  for (var i = 0, len = pixels.length; i < len; i += 4) {
    num or = pixels[i] / 255.0;
    num og = pixels[i + 1] / 255.0;
    num ob = pixels[i + 2] / 255.0;

    var r = or;
    var g = og;
    var b = ob;

    if (br != null) {
      r = pow((r + br) * wr, mr);
      g = pow((g + bg) * wg, mg);
      b = pow((b + bb) * wb, mb);
    }

    if (brightness != null && brightness != 1.0) {
      var b = brightness.clamp(0, 1000);
      r *= b;
      g *= b;
      b *= b;
    }

    if (saturation != null) {
      var lum = r * lumCoeffR + g * lumCoeffG + b * lumCoeffB;

      r = lum * invSaturation + r * saturation;
      g = lum * invSaturation + g * saturation;
      b = lum * invSaturation + b * saturation;
    }

    if (contrast != null) {
      r = avgLumR * invContrast + r * contrast;
      g = avgLumG * invContrast + g * contrast;
      b = avgLumB * invContrast + b * contrast;
    }

    if (gamma != null) {
      r = pow(r, gamma);
      g = pow(g, gamma);
      b = pow(b, gamma);
    }

    if (exposure != null) {
      r = r * exposure;
      g = g * exposure;
      b = b * exposure;
    }

    if (hue != null && hue != 0.0) {
      var hr = r * hueR + g * hueG + b * hueB;
      var hg = r * hueB + g * hueR + b * hueG;
      var hb = r * hueG + g * hueB + b * hueR;

      r = hr;
      g = hg;
      b = hb;
    }

    if (amount != null) {
      r = r * amount + or * invAmount;
      g = g * amount + og * invAmount;
      b = b * amount + ob * invAmount;
    }

    pixels[i] = clamp255((r * 255.0).toInt());
    pixels[i + 1] = clamp255((g * 255.0).toInt());
    pixels[i + 2] = clamp255((b * 255.0).toInt());
  }

  return src;
}