2 static char *RCSid() { return RCSid("$Id: getcolor.c,v 1.24 2006/02/21 09:14:49 mikulik Exp $"); }
5 /* GNUPLOT - getcolor.c */
9 * Petr Mikulik, December 1998 -- June 1999
10 * Copyright: open source as much as possible
22 * This file implements all the gray to color transforms except one:
23 * calculate_color_from_formulae() which can be found in color.c.
24 * calculate_color_from_formulae() belongs logicaly into this (getcolor.c)
25 * file, but it can't be here due to linkage problems: gnuplot_x11
26 * needs a lot of code from getcolor.c but does not contain any function
27 * evaluation code [and does not call calculate_color_from_formulae()].
28 * This file is compiled twice: Once as part of gnuplot and the second
29 * time with -DGPLT_X11_MODE resulting in getcolor_x11.o which is linked
30 * into gnuplot_x11. With GPLT_X11_MODE defined this file does not
31 * contain code for calculating colors from gray by user defined functions.
34 static int calculate_color_from_formulae __PROTO((double, rgb_color *));
37 static char *dbl_to_str __PROTO((double val, char *dest));
38 static double str_to_dbl __PROTO((char *s));
39 static void color_components_from_gray __PROTO((double gray, rgb_color *color));
40 static char *color_to_str __PROTO((rgb_color col, char *buf));
41 static void str_to_color __PROTO((char *buf, rgb_color *col));
42 static int interpolate_color_from_gray __PROTO((double, rgb_color *));
43 static double get_max_dev __PROTO((rgb_color *colors, int j, double limit));
44 static int is_extremum __PROTO((rgb_color left,rgb_color mid,rgb_color right));
45 static void CMY_2_RGB __PROTO((rgb_color *color));
46 static void CIEXYZ_2_RGB __PROTO((rgb_color *color));
47 static void YIQ_2_RGB __PROTO((rgb_color *color));
48 static void HSV_2_RGB __PROTO((rgb_color *color));
51 /* check if two palettes p1 and p2 differ significantly */
53 palettes_differ(t_sm_palette *p1, t_sm_palette *p2)
55 if (p1->colorMode != p2->colorMode)
57 if (p1->positive != p2->positive)
59 if (p1->cmodel != p2->cmodel)
61 if (p1->use_maxcolors != p2->use_maxcolors)
64 switch(p1->colorMode) {
65 case SMPAL_COLOR_MODE_NONE:
67 case SMPAL_COLOR_MODE_GRAY:
68 if (fabs(p1->gamma - p2->gamma) > 1e-3)
71 case SMPAL_COLOR_MODE_RGB:
72 if (p1->colorFormulae != p2->colorFormulae)
74 if (p1->formulaR != p2->formulaR)
76 if (p1->formulaG != p2->formulaG)
78 if (p1->formulaB != p2->formulaB)
80 /* if (p1->ps_allcF != p2->ps_allcF)
83 case SMPAL_COLOR_MODE_FUNCTIONS:
84 /* coarse check based on typed fnct definitions */
85 if (strcmp(p1->Afunc.definition, p2->Afunc.definition))
87 if (strcmp(p1->Bfunc.definition, p2->Bfunc.definition))
89 if (strcmp(p1->Cfunc.definition, p2->Cfunc.definition))
92 case SMPAL_COLOR_MODE_GRADIENT: {
95 if (p1->gradient_num != p2->gradient_num)
97 for(i=0; i<p1->gradient_num; ++i) {
98 if (p1->gradient[i].pos != p2->gradient[i].pos)
100 if (p1->gradient[i].col.r != p2->gradient[i].col.r)
102 if (p1->gradient[i].col.g != p2->gradient[i].col.g)
104 if (p1->gradient[i].col.b != p2->gradient[i].col.b)
108 } /* case GRADIENT */
111 return 0; /* no real difference found */
115 /* Store double value from [0,1] in 2 characters. Resolution is 6.1e-5.
116 * No '\n' are generated. */
117 static char *dbl_to_str(double val, char *dest)
119 unsigned int ival = (unsigned int) (((1 << 14) - 1) * val);
121 dest[0] = (ival >> 7) + 33;
122 dest[1] = (ival & 127) + 33;
126 /* Reverse of dbl_to_str(): map 2 characters to double in [0,1] */
131 (((unsigned int) (s[0] - 33) & 127) << 7)
132 | (unsigned int) ((s[1] - 33) & 127);
133 double val = ((double) ival) / ((1 << 14) - 1);
139 /* Save rgb_color to 6 characters which are no '\n'. */
141 *color_to_str(rgb_color col, char *buf)
143 dbl_to_str(col.r, buf + 0);
144 dbl_to_str(col.g, buf + 2);
145 dbl_to_str(col.b, buf + 4);
150 /* Restore rgb_color from 6 characters */
152 str_to_color(char *buf, rgb_color *col)
154 col->r = str_to_dbl(buf + 0);
155 col->g = str_to_dbl(buf + 2);
156 col->b = str_to_dbl(buf + 4);
160 /* Store a gradient entry in 8 characters which do not contain '\n' */
162 gradient_entry_to_str(gradient_struct *gs)
165 dbl_to_str(gs->pos, buf);
166 color_to_str(gs->col, buf + 2);
170 /* Gestore gradient entry from string */
172 str_to_gradient_entry(char *s, gradient_struct *gs)
174 gs->pos = str_to_dbl(s);
175 str_to_color(s + 2, & (gs->col));
179 #define CONSTRAIN(x) ((x) < 0 ? 0 : ((x) > 1 ? 1 : (x)))
182 /* This one takes the gradient defined in sm_palette.gradient and
183 * returns an interpolated color for the given gray value. It
184 * does not matter wether RGB or HSV or whatever values are stored
185 * in sm_palette.gradient[i].col, they will simply be interpolated.
186 * Return 0 on sucess, 1 if gray outside the range covered by the
187 * gradient. No gamma correction is done. The user can implement
188 * gamma correction specifying more points.
189 * sm_palette.gradient[] should be sorted acording to .pos.
190 * Returns 1 on failure and fills color with "nearest" color.
193 interpolate_color_from_gray(double gray, rgb_color *color)
200 color->r = sm_palette.gradient[0].col.r;
201 color->g = sm_palette.gradient[0].col.g;
202 color->b = sm_palette.gradient[0].col.b;
206 maxidx = sm_palette.gradient_num;
208 color->r = sm_palette.gradient[maxidx-1].col.r;
209 color->g = sm_palette.gradient[maxidx-1].col.g;
210 color->b = sm_palette.gradient[maxidx-1].col.b;
214 /* find index by bisecting */
217 int topidx = maxidx - 1;
218 /* treat idx as though it is bottom index */
219 while (idx != topidx) {
220 int tmpidx = (idx + topidx) / 2;
221 if (sm_palette.gradient[tmpidx].pos < gray)
222 idx = tmpidx + 1; /* round up */
228 col2 = & sm_palette.gradient[idx].col;
229 if (gray == sm_palette.gradient[idx].pos) {
235 /* linear interpolation of two colors */
236 double dx = sm_palette.gradient[idx].pos
237 - sm_palette.gradient[idx - 1].pos;
238 double f = (gray - sm_palette.gradient[idx-1].pos) / dx;
240 col1 = & sm_palette.gradient[idx - 1].col;
241 color->r = (col1->r + f * (col2->r - col1->r));
242 color->g = (col1->g + f * (col2->g - col1->g));
243 color->b = (col1->b + f * (col2->b - col1->b));
249 #ifndef GPLT_X11_MODE
250 /* Fills color with the values calculated from sm_palette.[ABC]func
251 * The color values are clipped to [0,1] without further notice.
252 * Returns 0 or does an int_error() when function evaluatin failed.
253 * The result is not in RGB color space jet.
256 calculate_color_from_formulae(double gray, rgb_color *color)
261 #define NO_CARET (-1)
263 (void) Gcomplex(&sm_palette.Afunc.dummy_values[0], gray, 0.0);
264 evaluate_at(sm_palette.Afunc.at, &v);
267 "Undefined value first color during function evaluation");
271 (void) Gcomplex(&sm_palette.Bfunc.dummy_values[0], gray, 0.0);
272 evaluate_at(sm_palette.Bfunc.at, &v);
275 "Undefined value second color during function evaluation");
279 (void) Gcomplex(&sm_palette.Cfunc.dummy_values[0], gray, 0.0);
280 evaluate_at(sm_palette.Cfunc.at, &v);
283 "Undefined value third color during function evaluation");
293 #endif /* !GPLT_X11_MODE */
296 /* Map gray in [0,1] to color components according to colorMode */
298 color_components_from_gray(double gray, rgb_color *color)
305 switch(sm_palette.colorMode) {
306 case SMPAL_COLOR_MODE_GRAY:
307 color->r = color->g = color->b = pow(gray, 1.0/sm_palette.gamma);
308 return; /* all done, no color space transformation needed */
309 case SMPAL_COLOR_MODE_RGB:
310 color->r = GetColorValueFromFormula(sm_palette.formulaR, gray);
311 color->g = GetColorValueFromFormula(sm_palette.formulaG, gray);
312 color->b = GetColorValueFromFormula(sm_palette.formulaB, gray);
314 case SMPAL_COLOR_MODE_GRADIENT:
315 interpolate_color_from_gray(gray, color);
317 #ifndef GPLT_X11_MODE
318 case SMPAL_COLOR_MODE_FUNCTIONS:
319 calculate_color_from_formulae(gray, color);
321 #endif /* !GPLT_X11_MODE */
323 fprintf(stderr, "%s:%d ooops: Unknown colorMode '%c'.\n",
324 __FILE__, __LINE__, (char)(sm_palette.colorMode));
329 * Map a gray value in [0,1] to the corresponding RGB values in [0,1],
330 * according to the current colorMode and color space.
332 * Note -- November 2003: this routine has been renamed from color_from_gray()
333 * to rgb1_from_gray() in order to more clearly distinguish structures
334 * rgb_color and rgb255_color.
337 rgb1_from_gray(double gray, rgb_color *color)
340 color_components_from_gray(gray, color);
341 if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY)
344 /* transform to RGB if necessary */
345 switch(sm_palette.cmodel) {
361 fprintf(stderr, "%s:%d ooops: Unknown color model '%c'\n",
362 __FILE__, __LINE__, (char)(sm_palette.cmodel));
368 * Convenience function to map R, G and B float values [0,1] to uchars [0,255].
371 rgb255_from_rgb1(rgb_color rgb1, rgb255_color *rgb255)
373 rgb255->r = (unsigned char)(255 * rgb1.r + 0.5);
374 rgb255->g = (unsigned char)(255 * rgb1.g + 0.5);
375 rgb255->b = (unsigned char)(255 * rgb1.b + 0.5);
380 * Convenience function to map gray values to R, G and B values in [0,1],
381 * taking care of palette maxcolors (i.e., discrete nb of colors).
384 rgb1maxcolors_from_gray(double gray, rgb_color *color)
386 if (sm_palette.use_maxcolors != 0)
387 gray = floor(gray * sm_palette.use_maxcolors)
388 / (sm_palette.use_maxcolors-1);
389 rgb1_from_gray(gray, color);
394 * Convenience function to map gray values to R, G and B values in [0,255],
395 * taking care of palette maxcolors (i.e., discrete nb of colors).
398 rgb255maxcolors_from_gray(double gray, rgb255_color *rgb255)
401 rgb1maxcolors_from_gray(gray, &rgb1);
402 rgb255_from_rgb1(rgb1, rgb255);
407 * Used by approximate_palette
410 get_max_dev(rgb_color *colors, int j, double limit)
412 double max_dev = 0.0;
413 double rdev, gdev, bdev;
414 double r=colors[0].r, g=colors[0].g, b=colors[0].b;
416 double sr = (colors[j].r - r) / j;
417 double sg = (colors[j].g - g) / j;
418 double sb = (colors[j].b - b) / j;
423 rdev = fabs(sr*dx + r - colors[i].r);
424 gdev = fabs(sg*dx + g - colors[i].g);
425 bdev = fabs(sb*dx + b - colors[i].b);
440 * Used by approximate_palette: true if one color component in mid
441 * is higher (or lower) than both left and right, flase other wise
444 is_extremum(rgb_color left, rgb_color mid, rgb_color right)
447 if(left.r < mid.r && mid.r > right.r)
449 if(left.g < mid.g && mid.g > right.g)
451 if(left.b < mid.b && mid.b > right.b)
455 if(left.r > mid.r && mid.r < right.r)
457 if(left.g > mid.g && mid.g < right.g)
459 if(left.b > mid.b && mid.b < right.b)
466 #define GROW_GRADIENT(n) do { \
467 if(cnt == gradient_size) { \
468 gradient_size += (n); \
469 gradient = (gradient_struct*) \
470 realloc(gradient, gradient_size * sizeof(gradient_struct)); \
476 * This function takes a palette and constructs a gradient which can
477 * be used to approximate the palette by linear interpolation.
478 * The palette is sampled at samples+1 points equally spaced in [0,1].
479 * From this huge gradient a much smaler one is constructed by selecting
480 * just those sampling points which still do approximate the full sampled
481 * one well enough. allowed_deviation determines the maximum deviation
482 * of all color components which is still acceptable for the reduced
483 * gradient. Use a sufficiently large number of samples (500 to 5000).
484 * Please free() the returned gradient after use. samples, allowed_deviation
485 * and max_skip may be <=0 and useful defaults will be used.
486 * Most probably it's useless to approximate a gradient- or rgbformulae-
487 * palette. Use it to build gradients from function palettes.
490 approximate_palette(t_sm_palette *palette, int samples,
491 double allowed_deviation,
496 int gradient_size=50;
497 gradient_struct *gradient;
503 /* int maximum_j=0, extrema=0; */
505 /* useful defaults */
508 if (allowed_deviation <= 0)
509 allowed_deviation = 0.003;
511 gradient = (gradient_struct*)
512 malloc(gradient_size * sizeof(gradient_struct));
513 colors = (rgb_color*) malloc(colors_size * sizeof(rgb_color));
514 assert(gradient && colors);
516 /* start (gray=0.0) is needed */
518 color_components_from_gray(0.0, colors + 0);
519 gradient[0].pos = 0.0;
520 gradient[0].col = colors[0];
522 color_components_from_gray(1.0 / samples, colors + 1);
524 for(i = 0; i < samples; ++i) {
525 for(j = 2; i + j <= samples; ++j) {
526 gray = ((double) (i + j)) / samples;
527 if (j == colors_size) {
529 colors = (rgb_color *)
530 realloc(colors, colors_size*sizeof(gradient_struct));
532 color_components_from_gray(gray, colors + j);
534 /* test for extremum */
535 if(is_extremum(colors[j - 2], colors[j - 1], colors[j])) {
536 /* fprintf(stderr,"Extremum at %g\n", gray); */
541 /* to big deviation */
542 max_dev = get_max_dev(colors, j, allowed_deviation);
543 if(max_dev > allowed_deviation) {
544 /* fprintf(stderr,"Control Point at %.3g\n",gray); */
550 gradient[cnt].pos = gray;
551 gradient[cnt].col = colors[j - 1];
554 /* if(j-1 > maximum_j) maximum_j = j-1; */
556 colors[0] = colors[j - 1];
557 colors[1] = colors[j];
561 color_components_from_gray(1.0, &color);
563 gradient[cnt].pos = 1.0;
564 gradient[cnt].col = color;
569 "PS interpolation table: %d samples, allowed deviation %.2f%%:\n",
570 samples, 100*allowed_deviation);
572 fprintf(stderr, " --> new size %d, %d extrema, max skip %d\n",
573 cnt, extrema, maximum_j);
577 return gradient; /* don't forget to free() it once you'r done with it */
584 * Original fixed color transformations
587 GetColorValueFromFormula(int formula, double x)
589 /* the input gray x is supposed to be in interval [0,1] */
590 if (formula < 0) { /* negate the value for negative formula */
619 x = sin(90 * x * DEG2RAD);
622 x = cos(90 * x * DEG2RAD);
628 x = (2 * x - 1) * (2.0 * x - 1);
631 x = sin(180 * x * DEG2RAD);
634 x = fabs(cos(180 * x * DEG2RAD));
637 x = sin(360 * x * DEG2RAD);
640 x = cos(360 * x * DEG2RAD);
643 x = fabs(sin(360 * x * DEG2RAD));
646 x = fabs(cos(360 * x * DEG2RAD));
649 x = fabs(sin(720 * x * DEG2RAD));
652 x = fabs(cos(720 * x * DEG2RAD));
676 x = fabs(1.5 * x - 0.5);
679 x = fabs(1.5 * x - 1);
686 x = x / 0.32 - 0.78125;
699 x = (x <= 0.92) ? -2 * x + 1.84 : x / 0.08 - 11.5;
702 x = fabs(2 * x - 0.5);
714 IMPORTANT: if any new formula is added here, then:
715 (1) its postscript counterpart must be added into term/post.trm,
716 search for "ps_math_color_formulae[]"
717 (2) number of colours must be incremented in color.c: variable
718 sm_palette, first item---search for "t_sm_palette sm_palette = "
721 fprintf(stderr, "Fatal: undefined color formula (can be 0--%i)\n", sm_palette.colorFormulae - 1);
732 /* Implementation of pm3dGetColorValue() in the postscript way.
733 Notice that the description, i.e. the part after %, is important
734 since it is used in `show pm3d' for displaying the analytical formulae.
735 The postscript formulae will be expanded into lines like:
736 "/cF0 {pop 0} bind def\t% 0",
737 "/cF4 {dup mul} bind def\t% x^2",
740 const char *ps_math_color_formulae[] = {
741 /* /cF0 */ "pop 0", "0",
742 /* /cF1 */ "pop 0.5", "0.5",
743 /* /cF2 */ "pop 1", "1",
745 /* /cF4 */ "dup mul", "x^2",
746 /* /cF5 */ "dup dup mul mul", "x^3",
747 /* /cF6 */ "dup mul dup mul", "x^4",
748 /* /cF7 */ "sqrt", "sqrt(x)",
749 /* /cF8 */ "sqrt sqrt", "sqrt(sqrt(x))",
750 /* /cF9 */ "90 mul sin", "sin(90x)",
751 /* /cF10 */ "90 mul cos", "cos(90x)",
752 /* /cF11 */ "0.5 sub abs", "|x-0.5|",
753 /* /cF12 */ "2 mul 1 sub dup mul", "(2x-1)^2",
754 /* /cF13 */ "180 mul sin", "sin(180x)",
755 /* /cF14 */ "180 mul cos abs", "|cos(180x)|",
756 /* /cF15 */ "360 mul sin", "sin(360x)",
757 /* /cF16 */ "360 mul cos", "cos(360x)",
758 /* /cF17 */ "360 mul sin abs", "|sin(360x)|",
759 /* /cF18 */ "360 mul cos abs", "|cos(360x)|",
760 /* /cF19 */ "720 mul sin abs", "|sin(720x)|",
761 /* /cF20 */ "720 mul cos abs", "|cos(720x)|",
762 /* /cF21 */ "3 mul", "3x",
763 /* /cF22 */ "3 mul 1 sub", "3x-1",
764 /* /cF23 */ "3 mul 2 sub", "3x-2",
765 /* /cF24 */ "3 mul 1 sub abs", "|3x-1|",
766 /* /cF25 */ "3 mul 2 sub abs", "|3x-2|",
767 /* /cF26 */ "1.5 mul .5 sub", "(3x-1)/2",
768 /* /cF27 */ "1.5 mul 1 sub", "(3x-2)/2",
769 /* /cF28 */ "1.5 mul .5 sub abs", "|(3x-1)/2|",
770 /* /cF29 */ "1.5 mul 1 sub abs", "|(3x-2)/2|",
771 /* /cF30 */ "0.32 div 0.78125 sub", "x/0.32-0.78125",
772 /* /cF31 */ "2 mul 0.84 sub", "2*x-0.84",
773 /* /cF32 */ "dup 0.42 le {4 mul} {dup 0.92 le {-2 mul 1.84 add} {0.08 div 11.5 sub} ifelse} ifelse",
774 "4x;1;-2x+1.84;x/0.08-11.5",
775 /* /cF33 */ "2 mul 0.5 sub abs", "|2*x - 0.5|",
776 /* /cF34 */ "2 mul", "2*x",
777 /* /cF35 */ "2 mul 0.5 sub", "2*x - 0.5",
778 /* /cF36 */ "2 mul 1 sub", "2*x - 1",
783 * Color Conversion Algorithms
784 * taken from http://www.cs.rit.edu/~ncs/color/t_convert.html
785 * each color model should provide a conversion to RGB.
786 * RGB values are clipped to [0,1] as some colors in some
787 * models have no RGB value.
790 CMY_2_RGB(rgb_color *col)
796 col->r = CONSTRAIN(1.0 - c);
797 col->g = CONSTRAIN(1.0 - m);
798 col->b = CONSTRAIN(1.0 - y);
802 CIEXYZ_2_RGB(rgb_color *col)
809 col->r = CONSTRAIN( 1.9100 * x - 0.5338 * y - 0.2891 * z);
810 col->g = CONSTRAIN(-0.9844 * x + 1.9990 * y - 0.0279 * z);
811 col->b = CONSTRAIN( 0.0585 * x - 0.1187 * y - 0.9017 * z);
815 YIQ_2_RGB(rgb_color *col)
822 col->r = CONSTRAIN(y - 0.956 * i + 0.621 * q);
823 col->g = CONSTRAIN(y - 0.272 * i - 0.647 * q);
824 col->b = CONSTRAIN(y - 1.105 * i - 1.702 * q);
828 HSV_2_RGB(rgb_color *col)
830 double h,s,v, f,p,q,t;
836 if (s == 0) { /* achromatic (gray) */
837 col->r = col->g = col->b = v;
841 h *= 6.; /* h range in gnuplot is [0,1] and not the usual [0,360] */
846 t = v * (1.0 - s*(1.0-f));