/// <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> public static void gamma_correct(ColourSystem cs, ref double c) { double gamma; gamma = cs.gamma; if (gamma == 0) { /* Rec. 709 gamma correction. */ double cc = 0.018; if (c < cc) { c *= ((1.099 * System.Math.Pow(cc, 0.45)) - 0.099) / cc; } else { c = (1.099 * System.Math.Pow(c, 0.45)) - 0.099; } } else { /* Nonlinear colour = (Linear colour)^(1/gamma) */ c = System.Math.Pow(c, 1.0 / gamma); } }
/// <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 xyz_to_rgb(ColourSystem cs, double xc, double yc, double zc, ref double r, ref double g, ref 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.xRed; yr = cs.yRed; zr = 1 - (xr + yr); xg = cs.xGreen; yg = cs.yGreen; zg = 1 - (xg + yg); xb = cs.xBlue; yb = cs.yBlue; zb = 1 - (xb + yb); xw = cs.xWhite; yw = cs.yWhite; 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); }
public 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); }