/* Built-in test program which displays the x, y, and Z and RGB * values for black body spectra from 1000 to 10000 degrees kelvin. * When run, this program should produce the following output: * * Temperature x y z R G B * ----------- ------ ------ ------ ----- ----- ----- * 1000 K 0.6528 0.3444 0.0028 1.000 0.007 0.000 (Approximation) * 1500 K 0.5857 0.3931 0.0212 1.000 0.126 0.000 (Approximation) * 2000 K 0.5267 0.4133 0.0600 1.000 0.234 0.010 * 2500 K 0.4770 0.4137 0.1093 1.000 0.349 0.067 * 3000 K 0.4369 0.4041 0.1590 1.000 0.454 0.151 * 3500 K 0.4053 0.3907 0.2040 1.000 0.549 0.254 * 4000 K 0.3805 0.3768 0.2428 1.000 0.635 0.370 * 4500 K 0.3608 0.3636 0.2756 1.000 0.710 0.493 * 5000 K 0.3451 0.3516 0.3032 1.000 0.778 0.620 * 5500 K 0.3325 0.3411 0.3265 1.000 0.837 0.746 * 6000 K 0.3221 0.3318 0.3461 1.000 0.890 0.869 * 6500 K 0.3135 0.3237 0.3628 1.000 0.937 0.988 * 7000 K 0.3064 0.3166 0.3770 0.907 0.888 1.000 * 7500 K 0.3004 0.3103 0.3893 0.827 0.839 1.000 * 8000 K 0.2952 0.3048 0.4000 0.762 0.800 1.000 * 8500 K 0.2908 0.3000 0.4093 0.711 0.766 1.000 * 9000 K 0.2869 0.2956 0.4174 0.668 0.738 1.000 * 9500 K 0.2836 0.2918 0.4246 0.632 0.714 1.000 * 10000 K 0.2807 0.2884 0.4310 0.602 0.693 1.000 */ int DoJob() { double t, x = 0, y = 0, z = 0, r = 0, g = 0, b = 0; colourSystem cs = colourSystem.SMPTEsystem; Console.WriteLine("Temperature x y z R G B\n"); Console.WriteLine("----------- ------ ------ ------ ----- ----- -----\n"); for (t = 1000; t <= 10000; t += 500) { bbTemp = t; spectrum_to_xyz(bb_spectrum, ref x, ref y, ref z); xyz_to_rgb(cs, x, y, z, ref r, ref g, ref b); Console.WriteLine(" {0,5:0} K %.4f %.4f %.4f ", t, x, y, z); if (constrain_rgb(ref r, ref g, ref b)) { norm_rgb(ref r, ref g, ref b); Console.WriteLine("%.3f %.3f %.3f (Approximation)\n", r, g, b); } else { norm_rgb(ref r, ref g, ref b); Console.WriteLine("%.3f %.3f %.3f\n", r, g, b); } } return(0); }
/* GAMMA_CORRECT_RGB * * 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 */ void gamma_correct(colourSystem cs, ref double c) { double gamma; gamma = cs.gamma; if (gamma == 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); } }
/* XYZ_TO_RGB * * 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. * */ 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); }
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); }