void color_init() { double x, y, z, r, g, b; struct colourSystem* cs = &SMPTEsystem; for(int ii = 0; ii < TEMP_ENTRIES; ++ii) { double temp = base_temp + step * ii; bbTemp = temp; spectrum_to_xyz(bb_spectrum, &x, &y, &z); xyz_to_rgb(cs, x, y, z, &r, &g, &b); constrain_rgb(&r, &g, &b); norm_rgb(&r, &g, &b); temp_table[ii][0] = r; temp_table[ii][1] = g; temp_table[ii][2] = b; } }
void spectrum(double t1, double t2, int N, unsigned char *d) { int i,j,dj; double X,Y,Z,R,G,B,L,M,S, Lw, Mw, Sw; struct colourSystem *cs = &CIEsystem; j = 0; dj = 1; if (t1<t2) { double t = t1; t1 = t2; t2 = t; j = N-1; dj=-1; } for (i=0; i<N; i++) { bbTemp = t1 + (t2-t1)/N*i; // integrate blackbody radiation spectrum to XYZ spectrum_to_xyz(bb_spectrum, &X, &Y, &Z); // normalize highest temperature to white (in LMS system) xyz_to_lms(X,Y,Z,&L,&M,&S); if (i==0) { Lw=1/L; Mw=1/M; Sw=1/S; } L *= Lw; M *= Mw; S *= Sw; lms_to_xyz(L,M,S,&X,&Y,&Z); // convert to RGB xyz_to_rgb(cs, X, Y, Z, &R, &G, &B); constrain_rgb(&R, &G, &B); norm_rgb(&R, &G, &B); d[(j<<2)] = (unsigned char) ((double)R*255); d[(j<<2)+1] = (unsigned char) ((double)G*255); d[(j<<2)+2] = (unsigned char) ((double)B*255); d[(j<<2)+3] = (B>0.1)? B*255 : 0; j += dj; } }
int main() { float t, x, y, z, r, g, b; struct colourSystem *cs = &SMPTEsystem; printf("Temperature x y z R G B\n"); printf("----------- ------ ------ ------ ----- ----- -----\n"); for (t = 1000; t <= 10000; t+= 500) { bbTemp = t; spectrum_to_xyz(bb_spectrum, &x, &y, &z); xyz_to_rgb(cs, x, y, z, &r, &g, &b); printf(" %5.0f K %.4f %.4f %.4f ", t, x, y, z); if (constrain_rgb(&r, &g, &b)) { norm_rgb(&r, &g, &b); printf("%.3f %.3f %.3f (Approximation)\n", r, g, b); } else { norm_rgb(&r, &g, &b); printf("%.3f %.3f %.3f\n", r, g, b); } } return 0; }
static void plotMonochromeWavelengths( pixel ** const pixels, int const pixcols, int const pixrows, pixval const maxval, const struct colorSystem * const cs, bool const upvp, int const xBias, int const yBias) { int const pxcols = pixcols - xBias; int const pxrows = pixrows - yBias; int x; /* The wavelength we're plotting */ for (x = (upvp? 420 : 450); x <= 650; x += (upvp? 10 : (x > 470 && x < 600) ? 5 : 10)) { pixel rgbcolor; /* Ick. Drop legends that overlap and twiddle position so they appear at reasonable positions with respect to the tongue. */ if (!overlappingLegend(upvp, x)) { double cx, cy, cz, jr, jg, jb, jmax; char wl[20]; int bx = 0, by = 0, tx, ty, r, g, b; int icx, icy; /* Location of the color on the tongue */ if (x < 520) { bx = Sz(-22); by = Sz(2); } else if (x < 535) { bx = Sz(-8); by = Sz(-6); } else { bx = Sz(4); } computeMonochromeColorLocation(x, pxcols, pxrows, upvp, &icx, &icy); /* Draw the tick mark */ PPM_ASSIGN(rgbcolor, maxval, maxval, maxval); tx = icx + ((x < 520) ? Sz(-2) : ((x >= 535) ? Sz(2) : 0)); ty = icy + ((x < 520) ? 0 : ((x >= 535) ? Sz(-1) : Sz(-2))); ppmd_line(pixels, pixcols, pixrows, Maxval, B(icx, icy), B(tx, ty), PPMD_NULLDRAWPROC, (char *) &rgbcolor); /* The following flailing about sets the drawing color to the hue corresponding to the pure wavelength (constrained to the display gamut). */ if (upvp) { double up, vp; up = ((double) icx) / (pxcols - 1); vp = 1.0 - ((double) icy) / (pxrows - 1); upvp_to_xy(up, vp, &cx, &cy); cz = 1.0 - (cx + cy); } else { cx = ((double) icx) / (pxcols - 1); cy = 1.0 - ((double) icy) / (pxrows - 1); cz = 1.0 - (cx + cy); } xyz_to_rgb(cs, cx, cy, cz, &jr, &jg, &jb); (void) constrain_rgb(&jr, &jg, &jb); /* Scale to max(rgb) = 1 */ jmax = MAX(jr, MAX(jg, jb)); if (jmax > 0) { jr = jr / jmax; jg = jg / jmax; jb = jb / jmax; } /* gamma correct from linear rgb to nonlinear rgb. */ gamma_correct_rgb(cs, &jr, &jg, &jb); r = Maxval * jr; g = Maxval * jg; b = Maxval * jb; PPM_ASSIGN(rgbcolor, (pixval) r, (pixval) g, (pixval) b); sprintf(wl, "%d", x); ppmd_text(pixels, pixcols, pixrows, Maxval, B(icx + bx, icy + by), Sz(6), 0, wl, PPMD_NULLDRAWPROC, (char *) &rgbcolor); } } }
static void fillInTongue(pixel ** const pixels, int const pixcols, int const pixrows, pixval const maxval, const struct colorSystem * const cs, bool const upvp, int const xBias, int const yBias, bool const highlightGamut) { int const pxcols = pixcols - xBias; int const pxrows = pixrows - yBias; int y; /* Scan the image line by line and fill the tongue outline with the RGB values determined by the color system for the x-y co-ordinates within the tongue. */ for (y = 0; y < pxrows; ++y) { bool present; /* There is some tongue on this line */ int leftEdge; /* x position of leftmost pixel in tongue on this line */ int rightEdge; /* same, but rightmost */ findTongue(pixels, pxcols, xBias, y, &present, &leftEdge, &rightEdge); if (present) { int x; for (x = leftEdge; x <= rightEdge; ++x) { double cx, cy, cz, jr, jg, jb, jmax; int r, g, b, mx; if (upvp) { double up, vp; up = ((double) x) / (pxcols - 1); vp = 1.0 - ((double) y) / (pxrows - 1); upvp_to_xy(up, vp, &cx, &cy); cz = 1.0 - (cx + cy); } else { cx = ((double) x) / (pxcols - 1); cy = 1.0 - ((double) y) / (pxrows - 1); cz = 1.0 - (cx + cy); } xyz_to_rgb(cs, cx, cy, cz, &jr, &jg, &jb); mx = Maxval; /* Check whether the requested color is within the gamut achievable with the given color system. If not, draw it in a reduced intensity, interpolated by desaturation to the closest within-gamut color. */ if (constrain_rgb(&jr, &jg, &jb)) { mx = highlightGamut ? Maxval : ((Maxval + 1) * 3) / 4; } /* Scale to max(rgb) = 1. */ jmax = MAX(jr, MAX(jg, jb)); if (jmax > 0) { jr = jr / jmax; jg = jg / jmax; jb = jb / jmax; } /* gamma correct from linear rgb to nonlinear rgb. */ gamma_correct_rgb(cs, &jr, &jg, &jb); r = mx * jr; g = mx * jg; b = mx * jb; PPM_ASSIGN(Bixels(y, x), (pixval) r, (pixval) g, (pixval) b); } } } }