I tried to implement this, and mostly failed. It's quite tricky to algorithmically generate the HCL part of the drawing, especially because HCL is so weird and out of bounds for RGB colorspaces.
I have nevertheless tried my best, and ended up with a compromise HSV-based display, but there's also code for HCL in there. Maybe someone can improve on this at some point... A. -- Le monochrome, c'est pour ceux qui s'intéressent (encore) au contenu. Usenet dans ces conditions, c'est comme le web avec lynx, on prend trop conscience du vide, c'est déprimant. - JLC dans le Guide du linuxien pervers: "Coup de cafard..."
/* * Screentest - CRT/LCD monitor testing utility. * http://screentest.sourceforge.net/ * Copyright (C) 2001 Jan "Yenya" Kasprzak <k...@fi.muni.cz> * Copyright (C) 2006-2007 Tobias Gruetzmacher <tob...@portfolio16.de> * Copyright (C) 2013 Antoine Beaupré <anar...@debian.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdio.h> #include <gtk/gtk.h> #include <assert.h> #include "callbacks.h" #include "gettext.h" #define GRID_STEP 64 // how many hues/brightness steps #define COLOR_STEP 12 #define RGB_COLOR_MAX (3*COLOR_STEP) #define CMYK_COLOR_MAX (4*COLOR_STEP) #define HCL_COLOR_MAX (12*COLOR_STEP) GdkColor rgb_colors[RGB_COLOR_MAX]; GdkColor cmyk_colors[CMYK_COLOR_MAX]; GdkColor hcl_colors[HCL_COLOR_MAX]; static void it8_hcl_to_rgb(GdkColor *color, guint h, gfloat c, gfloat l) { // intermediate values for HCL computations gfloat x, m; // temporary output values for rgb computations gfloat r, g, b; assert( 0 <= l); assert( l <= 1); assert( 0 <= c); assert( c <= 1); assert( 0 <= h); assert( h <= 360); // hold on to your butts: https://en.wikipedia.org/wiki/HSL_color_space#From_luma.2Fchroma.2Fhue x = c * ( 1 - abs(((h/60) % 2) -1) ); printf ("x: %f, c: %f, h: %d, abs: %d\n", x, c, h, abs(((h/60) % 2) -1)); switch (h/60) { case 0: r = c; g = x; b = 0; break; case 1: r = x; g = c; b = 0; break; case 2: r = 0; g = c; b = x; break; case 3: r = 0; g = x; b = c; break; case 4: r = x; g = 0; b = c; break; case 5: r = c; g = 0; b = x; break; default: r = g = b = 0; break; } printf("tmp: %f, %f, %f\n", r, g, b); // yes, this is magical m = l - ( 0.30 * r + 0.59 * g + 0.11 * b ); r += m; g += m; b += m; // cap to our colorspace r = r < 0 ? 0 : r; g = g < 0 ? 0 : g; b = b < 0 ? 0 : b; printf("rgb: %f, %f, %f (m: %f)\n", r, g, b, m); printf("hcl (%d, %f, %f) -> rgb 0x%02x%02x%02x\n", h, c, l, (int)(r*0xff), (int)(g*0xff), (int)(b*0xff)); r *= 0xffff; g *= 0xffff; b *= 0xffff; // scale up to 255, we cast to int below //printf("final rgb: (m: %f) %f, %f, %f\n", m, r, g, b); color->red = (gint)r; color->green = (gint)g; color->blue = (gint)b; // used to be: //return ((gint)r << 16) + ((gint)g << 8) + (gint)b; //hcl_colors[i].red = ( rgb & ( 255 << 16 ) ) >> 16; //hcl_colors[i].green = ( rgb & ( 255 << 8 ) ) >> 8; //hcl_colors[i].blue = rgb & ( 255 ); //printf("hcl -> rgb: (%d, %f, %f) -> (0x%x, 0x%x, 0x%x)\n", h, c, l, color->red, color->green, color->blue); } // taken from src/library/grDevices/src/colors.c in R 3.0.1 static void hsv2rgb(double h, double s, double v, double *r, double *g, double *b) { double f, p, q, t; int i; f = modf(h * 6.0, &t); i = ((int) t) % 6; p = v * (1 - s); q = v * (1 - s * f); t = v * (1 - (s * (1 - f))); switch (i) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; default: error("bad hsv to rgb color conversion"); } } /** * following functions are taken from src/library/grDevices/src/colors.c in R 3.0.1 */ /* D65 White Point */ #define WHITE_X 95.047 #define WHITE_Y 100.000 #define WHITE_Z 108.883 #define WHITE_u 0.1978398 #define WHITE_v 0.4683363 #ifndef DEG2RAD #define DEG2RAD 0.01745329251994329576 #endif /* Standard CRT Gamma */ #define GAMMA 2.4 static double gtrans(double u) { if (u > 0.00304) return 1.055 * pow(u, (1 / GAMMA)) - 0.055; else return 12.92 * u; } static void hcl2rgb(double h, double c, double l, double *R, double *G, double *B) { double L, U, V; double u, v; double X, Y, Z; /* Step 1 : Convert to CIE-LUV */ h = DEG2RAD * h; L = l; U = c * cos(h); V = c * sin(h); /* Step 2 : Convert to CIE-XYZ */ if (L <= 0 && U == 0 && V == 0) { X = 0; Y = 0; Z = 0; } else { Y = WHITE_Y * ((L > 7.999592) ? pow((L + 16)/116, 3) : L / 903.3); u = U / (13 * L) + WHITE_u; v = V / (13 * L) + WHITE_v; X = 9.0 * Y * u / (4 * v); Z = - X / 3 - 5 * Y + 3 * Y / v; } /* Step 4 : CIE-XYZ to sRGB */ *R = gtrans(( 3.240479 * X - 1.537150 * Y - 0.498535 * Z) / WHITE_Y); *G = gtrans((-0.969256 * X + 1.875992 * Y + 0.041556 * Z) / WHITE_Y); *B = gtrans(( 0.055648 * X - 0.204043 * Y + 1.057311 * Z) / WHITE_Y); } /** * end of imported functions */ static void it8_hcl_to_rgb2(GdkColor *color, double h, double s, double v) { double r, g, b; hcl2rgb(h, s, v, &r, &g, &b); if (r < 0) { r = 0; } else if (r > 1) { r = 1; } if (g < 0) { g = 0; } else if (g > 1) { g = 1; } if (b < 0) { b = 0; } else if (b > 1) { b = 1; } printf("hcl res: %f %f %f\n", r, g, b); color->red = (gint) (0xffff * r); color->green = (gint) (0xffff * g); color->blue = (gint) (0xffff * b); } static void it8_hsv_to_rgb2(GdkColor *color, double h, double s, double v) { double r, g, b; hsv2rgb(h/360, s, v, &r, &g, &b); color->red = (gint)(0xffff*r);color->green=(gint)(0xffff*g);color->blue=(gint)(0xffff*b); } #define RETURN_RGB(r,g,b) color->red = (gint)(0xffff*r);color->green=(gint)(0xffff*g);color->blue=(gint)(0xffff*b);break; // code stolen from colorspace.c in r-cran-colorspace-1.2.2 static void it8_hsv_to_rgb(GdkColor *color, gfloat h, gfloat s, gfloat v) { double m, n, f; int i; assert( 0 <= s); assert( s <= 1); assert( 0 <= v); assert( v <= 1); assert( 0 <= h); assert( h <= 360); h = h /60; /* convert to [0, 6] */ i = floor(h); f = h - i; if(!(i & 1)) /* if i is even */ f = 1 - f; m = v * (1 - s); n = v * (1 - s * f); switch (i) { case 6: case 0: RETURN_RGB(v, n, m); case 1: RETURN_RGB(n, v, m); case 2: RETURN_RGB(m, v, n); case 3: RETURN_RGB(m, n, v); case 4: RETURN_RGB(n, m, v); case 5: RETURN_RGB(v, m, n); } } static void it8_init(G_GNUC_UNUSED GtkWidget * widget) { gint i, j, n; gint rgb; gint h; gfloat s, v; memset(hcl_colors, 0, HCL_COLOR_MAX * sizeof(GdkColor)); n = 0; for (s = 1.0; s >= 0.20; s-=0.30) { for (v = 0.5; v <= 1.0; v+=0.15) { for (i = 0; i < COLOR_STEP; i++) { h = (i * (360/COLOR_STEP)) % 360; printf("%d hsv -> rgb: (%d, %f, %f) -> ", n, h, s, v); it8_hsv_to_rgb2(&hcl_colors[n], h, s, v) ; printf("(0x%04x%04x%04x)\n", hcl_colors[n].red, hcl_colors[n].green, hcl_colors[n].blue); n++; } } } memset(rgb_colors, 0, RGB_COLOR_MAX * sizeof(GdkColor)); for (i = 0; i < COLOR_STEP; i++) { rgb_colors[i].red = ((1 << 16) - 1); rgb_colors[i].green = i * ((1 << 16) - 1) / (COLOR_STEP - 1); rgb_colors[i].blue = i * ((1 << 16) - 1) / (COLOR_STEP - 1); } for (i = 0; i < COLOR_STEP; i++) { rgb_colors[i+COLOR_STEP].red = i * ((1 << 16) - 1) / (COLOR_STEP - 1); rgb_colors[i+COLOR_STEP].green = ((1 << 16) - 1); rgb_colors[i+COLOR_STEP].blue = i * ((1 << 16) - 1) / (COLOR_STEP - 1); } for (i = 0; i < COLOR_STEP; i++) { rgb_colors[i+2*COLOR_STEP].red = i * ((1 << 16) - 1) / (COLOR_STEP - 1); rgb_colors[i+2*COLOR_STEP].green = i * ((1 << 16) - 1) / (COLOR_STEP - 1); rgb_colors[i+2*COLOR_STEP].blue = ((1 << 16) - 1); } memset(cmyk_colors, 0, CMYK_COLOR_MAX * sizeof(GdkColor)); for (i = 0; i < COLOR_STEP; i++) { cmyk_colors[i].red = i * ((1 << 16) - 1) / (COLOR_STEP - 1); cmyk_colors[i].green = ((1 << 16) - 1); cmyk_colors[i].blue = ((1 << 16) - 1); } for (i = 0; i < COLOR_STEP; i++) { cmyk_colors[i+COLOR_STEP].red = ((1 << 16) - 1); cmyk_colors[i+COLOR_STEP].green = i * ((1 << 16) - 1) / (COLOR_STEP - 1); cmyk_colors[i+COLOR_STEP].blue = ((1 << 16) - 1); } for (i = 0; i < COLOR_STEP; i++) { cmyk_colors[i+2*COLOR_STEP].red = ((1 << 16) - 1); cmyk_colors[i+2*COLOR_STEP].green = ((1 << 16) - 1); cmyk_colors[i+2*COLOR_STEP].blue = i * ((1 << 16) - 1) / (COLOR_STEP - 1); } for (i = 0; i < COLOR_STEP; i++) { cmyk_colors[i+3*COLOR_STEP].red = i * ((1 << 16) - 1) / (COLOR_STEP - 1); cmyk_colors[i+3*COLOR_STEP].green = i * ((1 << 16) - 1) / (COLOR_STEP - 1); cmyk_colors[i+3*COLOR_STEP].blue = i * ((1 << 16) - 1) / (COLOR_STEP - 1); } } static void it8_draw(GtkWidget * widget) { GdkWindow *win = widget->window; gint w, h; // window size gint i; // counter gint d; // boxes size gint x_offset; // where we are vertically gint border = 20; gdk_window_get_size(win, &w, &h); d = w / 4; if (d > h / 4) d = h / 4; for (i = ((h - 1) % GRID_STEP) / 2; i < h; i += GRID_STEP) gdk_draw_line(win, gc, 0, i, w - 1, i); d = 20; d = ( h - 2*border ) / ( COLOR_STEP ); printf("h: %d, w: %d, d: %d\n", h, w, d); x_offset = border; for (i = 0; i < HCL_COLOR_MAX; i++) { gdk_gc_set_rgb_fg_color(gc, &hcl_colors[i]); gdk_draw_rectangle(win, gc, TRUE, x_offset + (i/COLOR_STEP) * d, border + (i % COLOR_STEP) * d, d, d); } x_offset += ((i+1)/COLOR_STEP) * d; for (i = 0; i < CMYK_COLOR_MAX; i++) { gdk_gc_set_rgb_fg_color(gc, &cmyk_colors[i]); gdk_draw_rectangle(win, gc, TRUE, x_offset + (i/COLOR_STEP) * d, border + (i % COLOR_STEP) * d, d, d); } x_offset += ((i+1)/COLOR_STEP) * d; for (i = 0; i < RGB_COLOR_MAX; i++) { gdk_gc_set_rgb_fg_color(gc, &rgb_colors[i]); gdk_draw_rectangle(win, gc, TRUE, x_offset + (i/COLOR_STEP) * d, border + (i % COLOR_STEP) * d, d, d); } } struct test_ops it8_ops = { init:it8_init, draw:it8_draw, cycle:NULL, close:NULL };
signature.asc
Description: Digital signature