/// <summary> /// Transform linear RGB values to nonlinear RGB values. Rec. /// 709 is ITU-R Recommendation BT. 709 (1990) ``Basic /// Parameter Values for the HDTV Standard for the Studio and /// for International Programme Exchange'', formerly CCIR Rec. /// 709. For details see /// /// http://www.poynton.com/ColorFAQ.html /// http://www.poynton.com/GammaFAQ.html /// /// </summary> /// <param name="cs"></param> /// <param name="c"></param> static void gamma_correct(ColourSystem cs, ref double c) { double gamma; gamma = cs.Gamma; if (gamma == ColourSystems.GAMMA_REC709) { // Rec. 709 gamma correction. double cc = 0.018; if (c < cc) { c *= ((1.099 * Math.Pow(cc, 0.45)) - 0.099) / cc; } else { c = (1.099 * Math.Pow(c, 0.45)) - 0.099; } } else { // Nonlinear colour = (Linear colour)^(1/gamma) c = Math.Pow(c, 1.0 / gamma); } }
public static Color FromTemp(this Color col, double temp, ColourSystem cs) { double r, g, b; RgbFromTemp(temp, out r, out g, out b, cs); return(Color.FromArgb(255, (int)r * 255, (int)r * 255, (int)r * 255)); }
static void gamma_correct_rgb(ColourSystem cs, ref double r, ref double g, ref double b) { gamma_correct(cs, ref r); gamma_correct(cs, ref g); gamma_correct(cs, ref b); }
/// <summary> /// Given an additive tricolour system CS, defined by the CIE x /// and y chromaticities of its three primaries (z is derived /// trivially as 1-(x+y)), and a desired chromaticity (XC, YC, /// ZC) in CIE space, determine the contribution of each /// primary in a linear combination which sums to the desired /// chromaticity. If the requested chromaticity falls outside /// the Maxwell triangle (colour gamut) formed by the three /// primaries, one of the r, g, or b weights will be negative. /// /// Caller can use constrain_rgb() to desaturate an /// outside-gamut colour to the closest representation within /// the available gamut and/or norm_rgb to normalise the RGB /// components so the largest nonzero component has value 1. /// </summary> /// <param name="cs"></param> /// <param name="xc"></param> /// <param name="yc"></param> /// <param name="zc"></param> /// <param name="r"></param> /// <param name="g"></param> /// <param name="b"></param> public static void XyzToRgb(ColourSystem cs, double xc, double yc, double zc, out double r, out double g, out double b) { double xr, yr, zr, xg, yg, zg, xb, yb, zb; double xw, yw, zw; double rx, ry, rz, gx, gy, gz, bx, by, bz; double rw, gw, bw; xr = cs.Red.X; yr = cs.Red.Y; zr = 1 - (xr + yr); xg = cs.Green.X; yg = cs.Green.Y; zg = 1 - (xg + yg); xb = cs.Blue.X; yb = cs.Blue.Y; zb = 1 - (xb + yb); xw = cs.White.X; yw = cs.White.Y; zw = 1 - (xw + yw); // xyz -> rgb matrix, before scaling to white. rx = (yg * zb) - (yb * zg); ry = (xb * zg) - (xg * zb); rz = (xg * yb) - (xb * yg); gx = (yb * zr) - (yr * zb); gy = (xr * zb) - (xb * zr); gz = (xb * yr) - (xr * yb); bx = (yr * zg) - (yg * zr); by = (xg * zr) - (xr * zg); bz = (xr * yg) - (xg * yr); // White scaling factors. // Dividing by yw scales the white luminance to unity, as conventional. rw = ((rx * xw) + (ry * yw) + (rz * zw)) / yw; gw = ((gx * xw) + (gy * yw) + (gz * zw)) / yw; bw = ((bx * xw) + (by * yw) + (bz * zw)) / yw; // xyz -> rgb matrix, correctly scaled to white. rx = rx / rw; ry = ry / rw; rz = rz / rw; gx = gx / gw; gy = gy / gw; gz = gz / gw; bx = bx / bw; by = by / bw; bz = bz / bw; // rgb of the desired point r = (rx * xc) + (ry * yc) + (rz * zc); g = (gx * xc) + (gy * yc) + (gz * zc); b = (bx * xc) + (by * yc) + (bz * zc); }
private static void RgbFromTemp(double temp, out double r, out double g, out double b, ColourSystem cs) { double x, y, z; Kernel.SpectrumToXyz((double waveLength) => { return(Kernel.BlackBodySpectrum(waveLength, temp)); }, out x, out y, out z); Kernel.XyzToRgb(cs, x, y, z, out r, out g, out b); if (Kernel.ConstrainRgb(ref r, ref g, ref b)) { Kernel.NormRgb(ref r, ref g, ref b); } else { Kernel.NormRgb(ref r, ref g, ref b); } }