w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ppmcie.c
Go to the documentation of this file.
1 /*
2 
3  Generate a PPM file representing a CIE colour gamut chart
4 
5  by John Walker -- kelvin@fourmilab.ch
6  WWW home page: http://www.fourmilab.ch/
7 
8  Permission to use, copy, modify, and distribute this software and
9  its documentation for any purpose and without fee is hereby
10  granted, without any conditions or restrictions. This software is
11  provided "as is" without express or implied warranty.
12 
13  This program was called ppmtocie in Walker's original work.
14  Because "cie" is not a graphics format, Bryan changed the name
15  when he integrated it into the Netpbm package.
16 
17 */
18 
19 #include <math.h>
20 #include "ppm.h"
21 #include "ppmdraw.h"
22 
23 #define CLAMP(v, l, h) ((v) < (l) ? (l) : (v) > (h) ? (h) : (v))
24 #define TRUE 1
25 #define FALSE 0
26 
27 #define Maxval 255 /* Maxval to use in generated pixmaps */
28 
29 /* A colour system is defined by the CIE x and y coordinates of its
30  three primary illuminants and the x and y coordinates of the white
31  point. */
32 
33 struct colourSystem {
34  char *name; /* Colour system name */
35  double xRed, yRed, /* Red primary illuminant */
36  xGreen, yGreen, /* Green primary illuminant */
37  xBlue, yBlue, /* Blue primary illuminant */
38  xWhite, yWhite; /* White point */
39 };
40 
41 /* The following table gives the CIE colour matching functions
42  \bar{x}(\lambda), \bar{y}(\lambda), and \bar{z}(\lambda), for
43  wavelengths \lambda at 5 nanometre increments from 380 nm through
44  780 nm. This table is used in conjunction with Planck's law for
45  the energy spectrum of a black body at a given temperature to plot
46  the black body curve on the CIE chart. */
47 
48 static double cie_colour_match[][3] = {
49  { 0.0014, 0.0000, 0.0065 }, /* 380 nm */
50  { 0.0022, 0.0001, 0.0105 },
51  { 0.0042, 0.0001, 0.0201 },
52  { 0.0076, 0.0002, 0.0362 },
53  { 0.0143, 0.0004, 0.0679 },
54  { 0.0232, 0.0006, 0.1102 },
55  { 0.0435, 0.0012, 0.2074 },
56  { 0.0776, 0.0022, 0.3713 },
57  { 0.1344, 0.0040, 0.6456 },
58  { 0.2148, 0.0073, 1.0391 },
59  { 0.2839, 0.0116, 1.3856 },
60  { 0.3285, 0.0168, 1.6230 },
61  { 0.3483, 0.0230, 1.7471 },
62  { 0.3481, 0.0298, 1.7826 },
63  { 0.3362, 0.0380, 1.7721 },
64  { 0.3187, 0.0480, 1.7441 },
65  { 0.2908, 0.0600, 1.6692 },
66  { 0.2511, 0.0739, 1.5281 },
67  { 0.1954, 0.0910, 1.2876 },
68  { 0.1421, 0.1126, 1.0419 },
69  { 0.0956, 0.1390, 0.8130 },
70  { 0.0580, 0.1693, 0.6162 },
71  { 0.0320, 0.2080, 0.4652 },
72  { 0.0147, 0.2586, 0.3533 },
73  { 0.0049, 0.3230, 0.2720 },
74  { 0.0024, 0.4073, 0.2123 },
75  { 0.0093, 0.5030, 0.1582 },
76  { 0.0291, 0.6082, 0.1117 },
77  { 0.0633, 0.7100, 0.0782 },
78  { 0.1096, 0.7932, 0.0573 },
79  { 0.1655, 0.8620, 0.0422 },
80  { 0.2257, 0.9149, 0.0298 },
81  { 0.2904, 0.9540, 0.0203 },
82  { 0.3597, 0.9803, 0.0134 },
83  { 0.4334, 0.9950, 0.0087 },
84  { 0.5121, 1.0000, 0.0057 },
85  { 0.5945, 0.9950, 0.0039 },
86  { 0.6784, 0.9786, 0.0027 },
87  { 0.7621, 0.9520, 0.0021 },
88  { 0.8425, 0.9154, 0.0018 },
89  { 0.9163, 0.8700, 0.0017 },
90  { 0.9786, 0.8163, 0.0014 },
91  { 1.0263, 0.7570, 0.0011 },
92  { 1.0567, 0.6949, 0.0010 },
93  { 1.0622, 0.6310, 0.0008 },
94  { 1.0456, 0.5668, 0.0006 },
95  { 1.0026, 0.5030, 0.0003 },
96  { 0.9384, 0.4412, 0.0002 },
97  { 0.8544, 0.3810, 0.0002 },
98  { 0.7514, 0.3210, 0.0001 },
99  { 0.6424, 0.2650, 0.0000 },
100  { 0.5419, 0.2170, 0.0000 },
101  { 0.4479, 0.1750, 0.0000 },
102  { 0.3608, 0.1382, 0.0000 },
103  { 0.2835, 0.1070, 0.0000 },
104  { 0.2187, 0.0816, 0.0000 },
105  { 0.1649, 0.0610, 0.0000 },
106  { 0.1212, 0.0446, 0.0000 },
107  { 0.0874, 0.0320, 0.0000 },
108  { 0.0636, 0.0232, 0.0000 },
109  { 0.0468, 0.0170, 0.0000 },
110  { 0.0329, 0.0119, 0.0000 },
111  { 0.0227, 0.0082, 0.0000 },
112  { 0.0158, 0.0057, 0.0000 },
113  { 0.0114, 0.0041, 0.0000 },
114  { 0.0081, 0.0029, 0.0000 },
115  { 0.0058, 0.0021, 0.0000 },
116  { 0.0041, 0.0015, 0.0000 },
117  { 0.0029, 0.0010, 0.0000 },
118  { 0.0020, 0.0007, 0.0000 },
119  { 0.0014, 0.0005, 0.0000 },
120  { 0.0010, 0.0004, 0.0000 },
121  { 0.0007, 0.0002, 0.0000 },
122  { 0.0005, 0.0002, 0.0000 },
123  { 0.0003, 0.0001, 0.0000 },
124  { 0.0002, 0.0001, 0.0000 },
125  { 0.0002, 0.0001, 0.0000 },
126  { 0.0001, 0.0000, 0.0000 },
127  { 0.0001, 0.0000, 0.0000 },
128  { 0.0001, 0.0000, 0.0000 },
129  { 0.0000, 0.0000, 0.0000 } /* 780 nm */
130 };
131 
132 /* The following table gives the spectral chromaticity co-ordinates
133  x(\lambda) and y(\lambda) for wavelengths in 5 nanometre increments
134  from 380 nm through 780 nm. These co-ordinates represent the
135  position in the CIE x-y space of pure spectral colours of the given
136  wavelength, and thus define the outline of the CIE "tongue"
137  diagram. */
138 
139 static double spectral_chromaticity[81][3] = {
140  { 0.1741, 0.0050 }, /* 380 nm */
141  { 0.1740, 0.0050 },
142  { 0.1738, 0.0049 },
143  { 0.1736, 0.0049 },
144  { 0.1733, 0.0048 },
145  { 0.1730, 0.0048 },
146  { 0.1726, 0.0048 },
147  { 0.1721, 0.0048 },
148  { 0.1714, 0.0051 },
149  { 0.1703, 0.0058 },
150  { 0.1689, 0.0069 },
151  { 0.1669, 0.0086 },
152  { 0.1644, 0.0109 },
153  { 0.1611, 0.0138 },
154  { 0.1566, 0.0177 },
155  { 0.1510, 0.0227 },
156  { 0.1440, 0.0297 },
157  { 0.1355, 0.0399 },
158  { 0.1241, 0.0578 },
159  { 0.1096, 0.0868 },
160  { 0.0913, 0.1327 },
161  { 0.0687, 0.2007 },
162  { 0.0454, 0.2950 },
163  { 0.0235, 0.4127 },
164  { 0.0082, 0.5384 },
165  { 0.0039, 0.6548 },
166  { 0.0139, 0.7502 },
167  { 0.0389, 0.8120 },
168  { 0.0743, 0.8338 },
169  { 0.1142, 0.8262 },
170  { 0.1547, 0.8059 },
171  { 0.1929, 0.7816 },
172  { 0.2296, 0.7543 },
173  { 0.2658, 0.7243 },
174  { 0.3016, 0.6923 },
175  { 0.3373, 0.6589 },
176  { 0.3731, 0.6245 },
177  { 0.4087, 0.5896 },
178  { 0.4441, 0.5547 },
179  { 0.4788, 0.5202 },
180  { 0.5125, 0.4866 },
181  { 0.5448, 0.4544 },
182  { 0.5752, 0.4242 },
183  { 0.6029, 0.3965 },
184  { 0.6270, 0.3725 },
185  { 0.6482, 0.3514 },
186  { 0.6658, 0.3340 },
187  { 0.6801, 0.3197 },
188  { 0.6915, 0.3083 },
189  { 0.7006, 0.2993 },
190  { 0.7079, 0.2920 },
191  { 0.7140, 0.2859 },
192  { 0.7190, 0.2809 },
193  { 0.7230, 0.2770 },
194  { 0.7260, 0.2740 },
195  { 0.7283, 0.2717 },
196  { 0.7300, 0.2700 },
197  { 0.7311, 0.2689 },
198  { 0.7320, 0.2680 },
199  { 0.7327, 0.2673 },
200  { 0.7334, 0.2666 },
201  { 0.7340, 0.2660 },
202  { 0.7344, 0.2656 },
203  { 0.7346, 0.2654 },
204  { 0.7347, 0.2653 },
205  { 0.7347, 0.2653 },
206  { 0.7347, 0.2653 },
207  { 0.7347, 0.2653 },
208  { 0.7347, 0.2653 },
209  { 0.7347, 0.2653 },
210  { 0.7347, 0.2653 },
211  { 0.7347, 0.2653 },
212  { 0.7347, 0.2653 },
213  { 0.7347, 0.2653 },
214  { 0.7347, 0.2653 },
215  { 0.7347, 0.2653 },
216  { 0.7347, 0.2653 },
217  { 0.7347, 0.2653 },
218  { 0.7347, 0.2653 },
219  { 0.7347, 0.2653 },
220  { 0.7347, 0.2653 } /* 780 nm */
221 };
222 
223 static pixel **pixels; /* Pixel map */
224 static int pixcols, pixrows; /* Pixel map size */
225 static int sxsize = 512, sysize = 512; /* X, Y size */
226 static int interpwp = FALSE; /* Interpolate to white point ? */
227 
228 /* Standard white point chromaticities. */
229 
230 #define IlluminantC 0.3101, 0.3162 /* For NTSC television */
231 #define IlluminantD65 0.3127, 0.3291 /* For EBU and SMPTE */
232 
233 static struct colourSystem
234  NTSCsystem = { "NTSC", 0.67, 0.33, 0.21, 0.71, 0.14, 0.08, IlluminantC },
235  EBUsystem = { "EBU (PAL/SECAM)", 0.64, 0.33, 0.29, 0.60, 0.15, 0.06, IlluminantD65 },
236  SMPTEsystem = { "SMPTE", 0.630, 0.340, 0.310, 0.595, 0.155, 0.070, IlluminantD65 },
237  HDTVsystem = { "HDTV", 0.670, 0.330, 0.210, 0.710, 0.150, 0.060, IlluminantD65 },
238  CIEsystem = { "CIE", 0.7355,0.2645,0.2658,0.7243,0.1669,0.0085, 0.3894,0.3324},
239  Customsystem = { "Custom", 0.64, 0.33, 0.29, 0.60, 0.15, 0.06, IlluminantD65 };
240 
241 static struct colourSystem *cs = &EBUsystem;
242 
243 /* XYZ_TO_RGB
244 
245  Given an additive tricolour system CS, defined by the CIE x and y
246  chromaticities of its three primaries (z is derived trivially as
247  1-(x+y)), and a desired chromaticity (XC, YC, ZC) in CIE space,
248  determine the contribution of each primary in a linear combination
249  which sums to the desired chromaticity. If the requested
250  chromaticity falls outside the Maxwell triangle (colour gamut)
251  formed by the three primaries, one of the r, g, or b weights will
252  be negative. Use inside_gamut() to test for a valid colour and
253  constrain_rgb() to desaturate an outside-gamut colour to the
254  closest representation within the available gamut. */
255 
256 static void xyz_to_rgb(cs, xc, yc, zc, r, g, b)
257  struct colourSystem *cs;
258  double xc, yc, zc;
259  double *r, *g, *b;
260 {
261  double xr, yr, zr, xg, yg, zg, xb, yb, zb;
262 
263  xr = cs->xRed; yr = cs->yRed; zr = 1 - (xr + yr);
264  xg = cs->xGreen; yg = cs->yGreen; zg = 1 - (xg + yg);
265  xb = cs->xBlue; yb = cs->yBlue; zb = 1 - (xb + yb);
266 
267  *r = (-xg*yc*zb + xc*yg*zb + xg*yb*zc - xb*yg*zc - xc*yb*zg + xb*yc*zg) /
268  (xr*yg*zb - xg*yr*zb - xr*yb*zg + xb*yr*zg + xg*yb*zr - xb*yg*zr);
269 
270  *g = (xr*yc*zb - xc*yr*zb - xr*yb*zc + xb*yr*zc + xc*yb*zr - xb*yc*zr) /
271  (xr*yg*zb - xg*yr*zb - xr*yb*zg + xb*yr*zg + xg*yb*zr - xb*yg*zr);
272 
273  *b = (xr*yg*zc - xg*yr*zc - xr*yc*zg + xc*yr*zg + xg*yc*zr - xc*yg*zr) /
274  (xr*yg*zb - xg*yr*zb - xr*yb*zg + xb*yr*zg + xg*yb*zr - xb*yg*zr);
275 }
276 
277 /* INSIDE_GAMUT
278 
279  Test whether a requested colour is within the gamut achievable
280  with the primaries of the current colour system. This amounts
281  simply to testing whether all the primary weights are
282  non-negative. */
283 
284 static int inside_gamut(r, g, b)
285  double r, g, b;
286 {
287  return r >= 0 && g >= 0 && b >= 0;
288 }
289 
290 /* CONSTRAIN-RGB
291 
292  If the requested RGB shade contains a negative weight for one of
293  the primaries, it lies outside the colour gamut accessible from
294  the given triple of primaries. Desaturate it by mixing with the
295  white point of the colour system so as to reduce the primary with
296  the negative weight to zero. This is equivalent to finding the
297  intersection on the CIE diagram of a line drawn between the white
298  point and and the requested color and the edge of the Maxwell
299  triangle formed by the three primaries. If INTERPWP is nonzero,
300  the white point defined by the sum of the three primary
301  illuminants is used instead of the colour system's actual white
302  point. While indefensible from the standpoint of colour theory,
303  this produces much better looking charts on computer monitors,
304  since the white points of most colour systems are well to the blue
305  of the white defined by the R = G = B = 1. */
306 
307 static int constrain_rgb(cs, x, y, z, r, g, b)
308  struct colourSystem *cs;
309  double *x, *y, *z, *r, *g, *b;
310 {
311  /* Is the contribution of one of the primaries negative ? */
312 
313  if (!inside_gamut(*r, *g, *b)) {
314  double par, wr, wg, wb, xw, yw;
315 
316  /* Determine the white point used in interpolating out of
317  gamut colours. If INTERPWP is set, the colour system's
318  white point is used. Otherwise, the white defined by an
319  equal mix of the three illuminants is taken as the origin
320  of the interpolation line drawn to the out of gamut colour. */
321 
322  if (interpwp) {
323  xw = cs->xWhite;
324  yw = cs->yWhite;
325  } else {
326  xw = (cs->xRed + cs->xGreen + cs->xBlue) / 3;
327  yw = (cs->yRed + cs->yGreen + cs->yBlue) / 3;
328  }
329 
330  /* Yes. Find the RGB mixing weights of the white point (we
331  assume the white point is in the gamut!). */
332 
333  xyz_to_rgb(cs, xw, yw, 1 - (xw + yw), &wr, &wg, &wb);
334 
335  /* Find the primary with negative weight and calculate the
336  parameter of the point on the vector from the white point
337  to the original requested colour in RGB space. */
338 
339  if (*r < *g && *r < *b) {
340  par = wr / (wr - *r);
341  } else if (*g < *r && *g < *b) {
342  par = wg / (wg - *g);
343  } else {
344  par = wb / (wb - *b);
345  }
346 
347  /* Since XYZ space is a linear transformation of RGB space, we
348  can find the XYZ space coordinates of the point where the
349  edge of the gamut intersects the vector from the white
350  point to the original colour by multiplying the parameter
351  in RGB space by the difference vector in XYZ space. */
352 
353  *x = CLAMP(xw + par * (*x - xw), 0, 1);
354  *y = CLAMP(yw + par * (*y - yw), 0, 1);
355  *z = CLAMP(1 - (*x + *y), 0, 1);
356 
357  /* Now finally calculate the gamut-constrained RGB weights. */
358 
359  *r = CLAMP(wr + par * (*r - wr), 0, 1);
360  *g = CLAMP(wg + par * (*g - wg), 0, 1);
361  *b = CLAMP(wb + par * (*b - wb), 0, 1);
362  return 1; /* Colour modified to fit RGB gamut */
363  }
364  return 0; /* Colour within RGB gamut */
365 }
366 
367 /* Main program. */
368 
370  int argc;
371  char *argv[];
372 {
373  int argn, x, y;
374  char *usage = "[-[no]black] [-[no]wpoint] [-full] [-interpwp]\n\
375  [-ntsc|-ebu|-smpte|-hdtv|-cie]\n\
376  [-red <x> <y> -green <x> <y> -blue <x> <y> -white <x> <y>]\n\
377  [-size <s>] [-xsize|-width <x>] [-ysize|-height <y>]";
378  int widspec = FALSE, hgtspec = FALSE,
379  ix, icx, icy, fx, fy, lx, ly, xBias, yBias, pxcols, pxrows;
380  pixel rgbcolour; /* Pixel used to clear pixmap */
381  int showWhite = TRUE; /* Show white point ? */
382  int showBlack = TRUE; /* Show black body curve ? */
383  int fullChart = FALSE; /* Fill entire tongue ? */
384  char sysdesc[256]; /* Colour system description */
385 
386  ppm_init(&argc, argv);
387  argn = 1;
388 
389  while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
390  if (pm_keymatch(argv[argn], "-xsize", 1) ||
391  pm_keymatch(argv[argn], "-width", 2)) {
392  if (widspec) {
393  pm_error("already specified a size/width/xsize");
394  }
395  argn++;
396  if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1))
397  pm_usage(usage);
398  widspec = TRUE;
399  } else if (pm_keymatch(argv[argn], "-ysize", 1) ||
400  pm_keymatch(argv[argn], "-height", 2)) {
401  if (hgtspec) {
402  pm_error("already specified a size/height/ysize");
403  }
404  argn++;
405  if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
406  pm_usage(usage);
407  hgtspec = TRUE;
408  } else if (pm_keymatch(argv[argn], "-size", 2)) {
409  if (hgtspec || widspec) {
410  pm_error("already specified a size/height/ysize");
411  }
412  argn++;
413  if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1))
414  pm_usage(usage);
415  sxsize = sysize;
416  hgtspec = widspec = TRUE;
417  } else if (pm_keymatch(argv[argn], "-ntsc", 1)) {
418  cs = &NTSCsystem;
419  } else if (pm_keymatch(argv[argn], "-ebu", 1)) {
420  cs = &EBUsystem;
421  } else if (pm_keymatch(argv[argn], "-smpte", 2)) {
422  cs = &SMPTEsystem;
423  } else if (pm_keymatch(argv[argn], "-hdtv", 2)) {
424  cs = &HDTVsystem;
425  } else if (pm_keymatch(argv[argn], "-cie", 1)) {
426  cs = &CIEsystem;
427  } else if (pm_keymatch(argv[argn], "-red", 1)) {
428  cs = &Customsystem;
429  argn++;
430  if ((argn == argc) ||
431  (sscanf(argv[argn], "%lf", &Customsystem.xRed) != 1))
432  pm_usage(usage);
433  argn++;
434  if ((argn == argc) ||
435  (sscanf(argv[argn], "%lf", &Customsystem.yRed) != 1))
436  pm_usage(usage);
437  } else if (pm_keymatch(argv[argn], "-green", 1)) {
438  cs = &Customsystem;
439  argn++;
440  if ((argn == argc) ||
441  (sscanf(argv[argn], "%lf", &Customsystem.xGreen) != 1))
442  pm_usage(usage);
443  argn++;
444  if ((argn == argc) ||
445  (sscanf(argv[argn], "%lf", &Customsystem.yGreen) != 1))
446  pm_usage(usage);
447  } else if (pm_keymatch(argv[argn], "-blue", 3)) {
448  cs = &Customsystem;
449  argn++;
450  if ((argn == argc) ||
451  (sscanf(argv[argn], "%lf", &Customsystem.xBlue) != 1))
452  pm_usage(usage);
453  argn++;
454  if ((argn == argc) ||
455  (sscanf(argv[argn], "%lf", &Customsystem.yBlue) != 1))
456  pm_usage(usage);
457  } else if (pm_keymatch(argv[argn], "-white", 2)) {
458  cs = &Customsystem;
459  argn++;
460  if ((argn == argc) ||
461  (sscanf(argv[argn], "%lf", &Customsystem.xWhite) != 1))
462  pm_usage(usage);
463  argn++;
464  if ((argn == argc) ||
465  (sscanf(argv[argn], "%lf", &Customsystem.yWhite) != 1))
466  pm_usage(usage);
467  } else if (pm_keymatch(argv[argn], "-black", 3)) {
468  showBlack = TRUE; /* Show black body curve */
469  } else if (pm_keymatch(argv[argn], "-wpoint", 2)) {
470  showWhite = TRUE; /* Show white point of colour system */
471  } else if (pm_keymatch(argv[argn], "-noblack", 3)) {
472  showBlack = FALSE; /* Show black body curve */
473  } else if (pm_keymatch(argv[argn], "-nowpoint", 3)) {
474  showWhite = FALSE; /* Show white point of colour system */
475  } else if (pm_keymatch(argv[argn], "-full", 1)) {
476  fullChart = TRUE; /* Fill whole tongue full-intensity */
477  } else if (pm_keymatch(argv[argn], "-interpwp", 1)) {
478  interpwp = TRUE; /* Interpolate colours to white point */
479  } else {
480  pm_usage(usage);
481  }
482  argn++;
483  }
484 
485  if (argn != argc) { /* Extra bogus arguments ? */
486  pm_usage(usage);
487  }
488 
489 #define Sz(x) (((x) * min(pixcols, pixrows)) / 512)
490 #define B(x, y) ((x) + xBias), (y)
491 #define Bixels(y, x) pixels[y][x + xBias]
492 
493  /* Allocate image buffer and clear it to black. */
494 
496  PPM_ASSIGN(rgbcolour, 0, 0, 0);
499  (char *) &rgbcolour);
500 
501  /* Partition into plot area and axes and establish subwindow. */
502 
503  xBias = Sz(32);
504  yBias = Sz(20);
505 
506  pxcols = pixcols - xBias;
507  pxrows = pixrows - yBias;
508 
509  /* Draw the CIE tongue outline. */
510 
512  for (x = 380; x <= 700; x += 5) {
513  double px, py;
514 
515  ix = (x - 380) / 5;
516  px = spectral_chromaticity[ix][0];
517  py = spectral_chromaticity[ix][1];
518  icx = px * (pxcols - 1);
519  icy = (pxrows - 1) - py * (pxrows - 1);
520  if (x > 380) {
522  B(lx, ly), B(icx, icy),
523  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
524  } else {
525  fx = icx;
526  fy = icy;
527  }
528  lx = icx;
529  ly = icy;
530  }
532  B(lx, ly), B(fx, fy),
533  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
534 
535  /* Now scan the image line by line and fill the tongue outline
536  with the RGB values determined by the colour system for the x-y
537  co-ordinates within the tongue. */
538 
539  for (y = 0; y < pxrows; y++) {
540  int xe;
541 
542  /* Find horizontal extents of tongue on this line. */
543 
544  for (x = 0; x < pxcols; x++) {
545  if (PPM_GETR(Bixels(y, x)) != 0) {
546 
547  for (xe = pxcols - 1; xe >= x; xe--) {
548  if (PPM_GETR(Bixels(y, xe)) != 0) {
549  break;
550  }
551  }
552  break;
553  }
554  }
555  if (x < pxcols) {
556  for ( ; x <= xe; x++) {
557  double cx, cy, cz, jr, jg, jb, jmax;
558  int r, g, b, mx;
559 
560  cx = ((double) x) / (pxcols - 1);
561  cy = 1.0 - ((double) y) / (pxrows - 1);
562  cz = 1.0 - (cx + cy);
563  xyz_to_rgb(cs, cx, cy, cz, &jr, &jg, &jb);
564 
565  mx = Maxval;
566 
567  /* Check whether the requested colour is within the
568  gamut achievable with the given colour system. If
569  not, draw it in a reduced intensity, interpolated
570  by desaturation to the closest within-gamut colour. */
571 
572  if (constrain_rgb(cs, &cx, &cy, &cz, &jr, &jg, &jb)) {
573  mx = fullChart ? Maxval :
574  ((Maxval + 1) * 3) / 4;
575  }
576  if (jr <= 1 || jg <= 1 || jb <= 1) {
577  jmax = max(jr, max(jg, jb));
578  if (!(jr < 0 || jg < 0 || jb < 0)) {
579  r = mx * (jr / jmax);
580  g = mx * (jg / jmax);
581  b = mx * (jb / jmax);
582  PPM_ASSIGN(Bixels(y, x),
583  (pixval) r, (pixval) g, (pixval) b);
584  }
585  }
586  }
587  }
588  }
589 
590  /* Draw the axes and bounding line. */
591 
594  B(0, 0), B(0, pxrows - 1), PPMD_NULLDRAWPROC, (char *) &rgbcolour);
596  B(0, pxrows - 1), B(pxcols - 1, pxrows - 1),
597  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
598 
599  /* Draw tick marks on X and Y axes every 0.1 units. Also label axes. */
600 
601  for (y = 1; y <= 9; y += 1) {
602  char s[20];
603 
604  /* X axis ticks */
605 
606  sprintf(s, "0.%d", y);
608  B((y * (pxcols - 1)) / 10, pxrows - Sz(1)),
609  B((y * (pxcols - 1)) / 10, pxrows - Sz(4)),
610  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
612  B((y * (pxcols - 1)) / 10 - Sz(11), pxrows + Sz(12)),
613  Sz(10), 0, s,
614  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
615 
616  /* Y axis ticks */
617 
618  sprintf(s, "0.%d", 10 - y);
620  B(0, (y * (pxrows - 1)) / 10),
621  B(Sz(3), (y * (pxrows - 1)) / 10),
622  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
624  B(Sz(-30), (y * (pxrows - 1)) / 10 + Sz(5)),
625  Sz(10), 0, s,
626  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
627  }
629  B((98 * (pxcols - 1)) / 100 - Sz(11), pxrows + Sz(12)),
630  Sz(10), 0, "X",
631  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
633  B(Sz(-22), (2 * (pxrows - 1)) / 100 + Sz(5)),
634  Sz(10), 0, "Y",
635  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
636 
637  /* Plot the white point of the chosen colour system. */
638 
639  if (showWhite) {
640  int wx = (pxcols - 1) * cs->xWhite,
641  wy = (pxrows - 1) - ((int) ((pxrows - 1) * cs->yWhite));
642 
643  PPM_ASSIGN(rgbcolour, 0, 0, 0);
644  /* We draw the four arms of the cross separately so as to
645  leave the pixel representing the precise white point
646  undisturbed. */
648  B(wx + Sz(1), wy), B(wx + Sz(3), wy),
649  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
651  B(wx - Sz(1), wy), B(wx - Sz(3), wy),
652  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
654  B(wx, wy + Sz(1)), B(wx, wy + Sz(3)),
655  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
657  B(wx, wy - Sz(1)), B(wx, wy - Sz(3)),
658  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
659  }
660 
661  /* Plot the black body curve. */
662 
663  if (showBlack) {
664  double t;
665 
666  PPM_ASSIGN(rgbcolour, 0, 0, 0);
667 
668  /* Plot black body curve from 1000 to 30000 degrees Kelvin. */
669 
670  for (t = 1000.0; t < 30000.0; t += 50.0) {
671  double lambda, X = 0, Y = 0, Z = 0;
672  int xb, yb;
673 
674  /* Determine X, Y, and Z for blackbody by summing colour
675  match functions over the visual range. */
676 
677  for (ix = 0, lambda = 380; lambda <= 780.0; ix++, lambda += 5) {
678  double Me;
679 
680  /* Evaluate Planck's black body equation for the
681  power at this wavelength. */
682 
683  Me = 3.74183e-16 * pow(lambda * 1e-9, -5.0) /
684  (exp(1.4388e-2/(lambda * 1e-9 * t)) - 1.0);
685  X += Me * cie_colour_match[ix][0];
686  Y += Me * cie_colour_match[ix][1];
687  Z += Me * cie_colour_match[ix][2];
688  }
689  xb = (pxcols - 1) * X / (X + Y + Z);
690  yb = (pxrows - 1) - ((pxrows - 1) * Y / (X + Y + Z));
691  if (t > 1000) {
693  B(lx, ly), B(xb, yb), PPMD_NULLDRAWPROC, (char *) &rgbcolour);
694 
695  /* Draw tick mark every 1000 degrees Kelvin */
696 
697  if ((((int) t) % 1000) == 0) {
699  B(lx, ly - Sz(2)), B(lx, ly + Sz(2)),
700  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
701 
702  /* Label selected tick marks with decreasing density. */
703 
704  if (t <= 8000.1 || (t > 8000.0 && ((((int) t) % 5000) == 0) && t != 20000.0)) {
705  char bb[20];
706 
707  sprintf(bb, "%g", t);
709  B(lx - Sz(12), ly - Sz(4)), Sz(6), 0, bb,
710  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
711  }
712 
713  }
714  }
715  lx = xb;
716  ly = yb;
717  }
718  }
719 
720  /* Plot wavelengths around periphery of the tongue. */
721 
722  for (x = 450; x <= 650; x += (x > 470 && x < 600) ? 5 :
723  10) {
724  double px, py, cx, cy, cz, jr, jg, jb, jmax;
725  char wl[20];
726  int bx = 0, by = 0, tx, ty, r, g, b;
727 
728  /* Ick. Drop legends that overlap and twiddle position
729  so they appear at reasonable positions with respect to
730  the tongue. */
731 
732  if (x == 460 || x == 630 || x == 640) {
733  continue;
734  }
735  if (x < 520) {
736  bx = Sz(-22);
737  by = Sz(2);
738  } else if (x < 535) {
739  bx = Sz(-8);
740  by = Sz(-6);
741  } else {
742  bx = Sz(4);
743  }
744 
745  ix = (x - 380) / 5;
746  px = spectral_chromaticity[ix][0];
747  py = spectral_chromaticity[ix][1];
748  icx = px * (pxcols - 1);
749  icy = (pxrows - 1) - py * (pxrows - 1);
750 
752  tx = icx + ((x < 520) ? Sz(-2) : ((x >= 535) ? Sz(2) : 0));
753  ty = icy + ((x < 520) ? 0 : ((x >= 535) ? Sz(-1) : Sz(-2)));
755  B(icx, icy), B(tx, ty),
756  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
757 
758  /* The following flailing about sets the drawing colour to
759  the hue corresponding to the pure wavelength (constrained
760  to the display gamut). */
761 
762  cx = ((double) icx) / (pxcols - 1);
763  cy = 1.0 - ((double) icy) / (pxrows - 1);
764  cz = 1.0 - (cx + cy);
765  xyz_to_rgb(cs, cx, cy, cz, &jr, &jg, &jb);
766  (void) constrain_rgb(cs, &cx, &cy, &cz, &jr, &jg, &jb);
767 
768  if (jr <= 1 || jg <= 1 || jb <= 1) {
769  jmax = max(jr, max(jg, jb));
770  if (!(jr < 0 || jg < 0 || jb < 0)) {
771  r = Maxval * (jr / jmax);
772  g = Maxval * (jg / jmax);
773  b = Maxval * (jb / jmax);
775  (pixval) r, (pixval) g, (pixval) b);
776  }
777  }
778 
779  sprintf(wl, "%d", x);
781  B(icx + bx, icy + by), Sz(6), 0, wl,
782  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
783  }
784 
785  /* Place description on chart. */
786 
788  sprintf(sysdesc, "System: %s\nPrimary illuminants (X, Y)\n\
789  Red: %0.4f, %0.4f\n\
790  Green: %0.4f, %0.4f\n\
791  Blue: %0.4f, %0.4f\n\
792 White point (X, Y): %0.4f, %0.4f",
793  cs->name, cs->xRed, cs->yRed, cs->xGreen, cs->yGreen,
794  cs->xBlue, cs->yBlue, cs->xWhite, cs->yWhite);
796  pixcols / 3, Sz(24), Sz(12), 0, sysdesc,
797  PPMD_NULLDRAWPROC, (char *) &rgbcolour);
798 
800  return 0;
801 }
double __cdecl exp(double _X)
double __cdecl pow(double _X, double _Y)
double wx
Definition: aftopl.c:57
static char mx
Definition: bmpfont.h:51
#define b
Definition: jpegint.h:372
int z
Definition: dviconv.c:26
int sscanf()
int pixels
Definition: dvipng.h:106
static void
Definition: fpif.c:118
#define s
Definition: afcover.h:80
#define t
Definition: afcover.h:96
static char usage[]
Definition: giftopnm.c:59
kerning y
Definition: ttdriver.c:212
int int cy
Definition: gdfx.h:13
int cx
Definition: gdfx.h:12
#define sprintf
Definition: snprintf.c:44
float x
Definition: cordic.py:15
void pm_usage(char *usage)
Definition: libpbm1.c:343
#define max(a, b)
Definition: pbmto4425.c:11
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF base if bpp PF set rept prefetch_distance PF set OFFSET endr endif endm macro preload_leading_step2 base if bpp ifc DST PF PF else if bpp lsl PF PF lsl PF PF lsl PF PF PF else PF lsl PF lsl PF lsl PF endif SIZE macro preload_middle scratch_holds_offset if bpp else PF PF endif endif endif endm macro preload_trailing base if bpp if bpp *pix_per_block PF PF lsl PF PF PF PF PF else PF lsl PF lsl PF PF PF PF PF base if bpp if narrow_case &&bpp<=dst_w_bpp) PF bic, WK0, base, #31 PF pld,[WK0] PF add, WK1, base, X, LSL #bpp_shift PF sub, WK1, WK1, #1 PF bic, WK1, WK1, #31 PF cmp, WK1, WK0 PF beq, 90f PF pld,[WK1]90:.else PF bic, WK0, base, #31 PF pld,[WK0] PF add, WK1, base, X, lsl #bpp_shift PF sub, WK1, WK1, #1 PF bic, WK1, WK1, #31 PF cmp, WK1, WK0 PF beq, 92f91:PF add, WK0, WK0, #32 PF cmp, WK0, WK1 PF pld,[WK0] PF bne, 91b92:.endif .endif.endm.macro conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, 0 .if decrementx sub &cond X, X, #8 *numbytes/dst_w_bpp .endif process_tail cond, numbytes, firstreg .if !((flags) &FLAG_PROCESS_DOES_STORE) pixst cond, numbytes, firstreg, DST .endif.endm.macro conditional_process1 cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx .if(flags) &FLAG_BRANCH_OVER .ifc cond, mi bpl 100f .endif .ifc cond, cs bcc 100f .endif .ifc cond, ne beq 100f .endif conditional_process1_helper, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx100:.else conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx .endif.endm.macro conditional_process2 test, cond1, cond2, process_head, process_tail, numbytes1, numbytes2, firstreg1, firstreg2, unaligned_src, unaligned_mask, decrementx .if(flags) &(FLAG_DST_READWRITE|FLAG_BRANCH_OVER|FLAG_PROCESS_CORRUPTS_PSR|FLAG_PROCESS_DOES_STORE) test conditional_process1 cond1, process_head, process_tail, numbytes1, firstreg1, unaligned_src, unaligned_mask, decrementx .if(flags) &FLAG_PROCESS_CORRUPTS_PSR test .endif conditional_process1 cond2, process_head, process_tail, numbytes2, firstreg2, unaligned_src, unaligned_mask, decrementx .else test process_head cond1, numbytes1, firstreg1, unaligned_src, unaligned_mask, 0 process_head cond2, numbytes2, firstreg2, unaligned_src, unaligned_mask, 0 .if decrementx sub &cond1 X, X, #8 *numbytes1/dst_w_bpp sub &cond2 X, X, #8 *numbytes2/dst_w_bpp .endif process_tail cond1, numbytes1, firstreg1 process_tail cond2, numbytes2, firstreg2 pixst cond1, numbytes1, firstreg1, DST pixst cond2, numbytes2, firstreg2, DST .endif.endm.macro test_bits_1_0_ptr .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 movs SCRATCH, X, lsl #32-1 .else movs SCRATCH, WK0, lsl #32-1 .endif.endm.macro test_bits_3_2_ptr .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 movs SCRATCH, X, lsl #32-3 .else movs SCRATCH, WK0, lsl #32-3 .endif.endm.macro leading_15bytes process_head, process_tail .set DECREMENT_X, 1 .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 .set DECREMENT_X, 0 sub X, X, WK0, lsr #dst_bpp_shift str X,[sp, #LINE_SAVED_REG_COUNT *4] mov X, WK0 .endif .if dst_w_bpp==8 conditional_process2 test_bits_1_0_ptr, mi, cs, process_head, process_tail, 1, 2, 1, 2, 1, 1, DECREMENT_X .elseif dst_w_bpp==16 test_bits_1_0_ptr conditional_process1 cs, process_head, process_tail, 2, 2, 1, 1, DECREMENT_X .endif conditional_process2 test_bits_3_2_ptr, mi, cs, process_head, process_tail, 4, 8, 1, 2, 1, 1, DECREMENT_X .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 ldr X,[sp, #LINE_SAVED_REG_COUNT *4] .endif.endm.macro test_bits_3_2_pix movs SCRATCH, X, lsl #dst_bpp_shift+32-3.endm.macro test_bits_1_0_pix .if dst_w_bpp==8 movs SCRATCH, X, lsl #dst_bpp_shift+32-1 .else movs SCRATCH, X, lsr #1 .endif.endm.macro trailing_15bytes process_head, process_tail, unaligned_src, unaligned_mask conditional_process2 test_bits_3_2_pix, cs, mi, process_head, process_tail, 8, 4, 0, 2, unaligned_src, unaligned_mask, 0 .if dst_w_bpp==16 test_bits_1_0_pix conditional_process1 cs, process_head, process_tail, 2, 0, unaligned_src, unaligned_mask, 0 .elseif dst_w_bpp==8 conditional_process2 test_bits_1_0_pix, cs, mi, process_head, process_tail, 2, 1, 0, 1, unaligned_src, unaligned_mask, 0 .endif.endm.macro wide_case_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, dst_alignment110:.set SUBBLOCK, 0 .rept pix_per_block *dst_w_bpp/128 process_head, 16, 0, unaligned_src, unaligned_mask, 1 .if(src_bpp > 0) &&(mask_bpp==0) &&((flags) &FLAG_PROCESS_PRESERVES_SCRATCH) preload_middle src_bpp, SRC, 1 .elseif(src_bpp==0) &&(mask_bpp > 0) &&((flags) &FLAG_PROCESS_PRESERVES_SCRATCH) preload_middle mask_bpp, MASK, 1 .else preload_middle src_bpp, SRC, 0 preload_middle mask_bpp, MASK, 0 .endif .if(dst_r_bpp > 0) &&((SUBBLOCK % 2)==0) &&(((flags) &FLAG_NO_PRELOAD_DST)==0) PF pld,[DST, #32 *prefetch_distance - dst_alignment] .endif process_tail, 16, 0 .if !((flags) &FLAG_PROCESS_DOES_STORE) pixst, 16, 0, DST .endif .set SUBBLOCK, SUBBLOCK+1 .endr subs X, X, #pix_per_block bhs 110b.endm.macro wide_case_inner_loop_and_trailing_pixels process_head, process_tail, process_inner_loop, exit_label, unaligned_src, unaligned_mask .if dst_r_bpp > tst bne process_inner_loop DST_PRELOAD_BIAS endif preload_trailing SRC preload_trailing MASK DST endif add medium_case_inner_loop_and_trailing_pixels unaligned_mask endm macro medium_case_inner_loop_and_trailing_pixels DST endif subs bhs tst beq exit_label trailing_15bytes unaligned_mask endm macro narrow_case_inner_loop_and_trailing_pixels unaligned_mask tst conditional_process1 trailing_15bytes unaligned_mask endm macro switch_on_alignment exit_label if bne endif if bne endif action if endif if bne endif action if endif endif endm macro end_of_line last_one if vars_spilled word LINE_SAVED_REGS endif subs Y
#define pm_error
Definition: png22pnm.c:118
#define pm_keymatch(stra, strb, _x)
Definition: png22pnm.c:121
void ppm_init(int *argcP, argv)
Definition: libppm1.c:21
void ppm_writeppm(FILE *file, pixel **pixels, int cols, int rows, pixval maxval, int forceplain)
Definition: libppm2.c:148
void ppmd_line(pixel **pixels, int cols, int rows, pixval maxval, int x0, int y0, int x1, int y1, void *drawprocP, char *clientdata)
Definition: libppm5.c:121
void ppmd_filledrectangle(pixel **pixels, int cols, int rows, pixval maxval, int x, int y, int width, int height, void *drawprocP, char *clientdata)
Definition: libppm5.c:47
void ppmd_text(pixel **pixels, int cols, int rows, pixval maxval, int x, int y, int height, int angle, char *s, void *drawprocP, char *clientdata)
Definition: libppm5.c:1043
#define PPM_GETR(p)
Definition: ppm.h:36
#define PPM_ASSIGN(p, red, grn, blu)
Definition: ppm.h:46
#define ppm_allocarray(cols, rows)
Definition: ppm.h:71
gray pixval
Definition: ppm.h:9
#define Sz(x)
static pixel ** pixels
Definition: ppmcie.c:223
#define IlluminantD65
Definition: ppmcie.c:231
#define Maxval
Definition: ppmcie.c:27
static struct colourSystem HDTVsystem
Definition: ppmcie.c:237
static int interpwp
Definition: ppmcie.c:226
#define IlluminantC
Definition: ppmcie.c:230
static struct colourSystem Customsystem
Definition: ppmcie.c:239
static int constrain_rgb(struct colourSystem *cs, double *x, double *y, double *z, double *r, double *g, double *b)
Definition: ppmcie.c:307
static int sxsize
Definition: ppmcie.c:225
static int pixrows
Definition: ppmcie.c:224
static struct colourSystem EBUsystem
Definition: ppmcie.c:235
static struct colourSystem * cs
Definition: ppmcie.c:241
#define B(x, y)
#define TRUE
Definition: ppmcie.c:24
#define FALSE
Definition: ppmcie.c:25
static double cie_colour_match[][3]
Definition: ppmcie.c:48
static struct colourSystem SMPTEsystem
Definition: ppmcie.c:236
static double spectral_chromaticity[81][3]
Definition: ppmcie.c:139
#define Bixels(y, x)
static int sysize
Definition: ppmcie.c:225
static struct colourSystem NTSCsystem
Definition: ppmcie.c:234
static void xyz_to_rgb(struct colourSystem *cs, double xc, double yc, double zc, double *r, double *g, double *b)
Definition: ppmcie.c:256
#define CLAMP(v, l, h)
Definition: ppmcie.c:23
static int inside_gamut(double r, double g, double b)
Definition: ppmcie.c:284
int main(int argc, argv)
Definition: ppmcie.c:369
static struct colourSystem CIEsystem
Definition: ppmcie.c:238
static int pixcols
Definition: ppmcie.c:224
#define PPMD_NULLDRAWPROC
Definition: ppmdraw.h:26
#define X
Definition: ppmforge.c:73
#define Z
Definition: ppmforge.c:75
static pixel rgbcolour
Definition: ppmlabel.c:27
int g
Definition: ppmqvga.c:68
int r
Definition: ppmqvga.c:68
ShellFileEnvironment e
Definition: sh6.c:388
double xWhite
Definition: ppmcie.c:38
double xRed
Definition: ppmcie.c:35
double yWhite
Definition: ppmcie.c:38
double xGreen
Definition: ppmcie.c:36
double xBlue
Definition: ppmcie.c:37
double yBlue
Definition: ppmcie.c:37
double yRed
Definition: ppmcie.c:35
char * name
Definition: ppmcie.c:34
double yGreen
Definition: ppmcie.c:36
Definition: pst1form.c:310
Definition: drvpic.cpp:36
Definition: ppm.h:33
Definition: dvips.h:235
return() int(((double) *(font_tbl[cur_fnt].wtbl+(int)(*(font_tbl[cur_fnt].char_wi+(int)(ch - font_tbl[cur_fnt].char_f)% 256)))/(double)(1L<< 20)) *(double) font_tbl[cur_fnt].scale)
#define argv
Definition: xmain.c:270
#define argc
Definition: xmain.c:269
#define argn