From: Greg T. <gd...@ir...> - 2007-06-10 17:12:04
|
I have been working on a patch to display value (essentially Y of XYZ, from 0-1) and Adam's zones (V is 0.18 - or maybe 0.20 depending on white reference, and each zone is one stop). With the patch, the spot measurement (which shows pixel values and can be used for WB) shows value and zone. I find this useful to put skin tones at the right place. The patch isn't quite finished - Udi suggested tooltips for what the numbers mean, but I haven't added eventboxes to make that work. If people (Udi :-) think this should go in, and that tooltips are the right way to go, I can add the eventboxes. Comments appreciated (code review, sensibility of intent, how should it be different, etc.). --- ufraw_preview.c.~1.102~ 2007-06-10 13:07:26.000000000 -0400 +++ ufraw_preview.c 2007-06-10 13:07:46.000000000 -0400 @@ -46,13 +46,15 @@ const int def_preview_height = 9000; #define max_scale 20 enum { pixel_format, percent_format }; +enum { without_zone, with_zone }; char *expanderText[] = { N_("Raw histogram"), N_("Live histogram"), NULL }; typedef struct { - GtkLabel *labels[4]; + GtkLabel *labels[5]; int num; int format; + int zonep; /* non-zero to display value/zone */ } colorLabels; typedef enum { render_default, render_overexposed, render_underexposed @@ -447,14 +449,22 @@ void load_profile(GtkWidget *widget, lon } colorLabels *color_labels_new(GtkTable *table, int x, int y, char *label, - int format) + int format, int zonep, preview_data *data) { colorLabels *l; GtkWidget *lbl; - int c, i = 0; + int c, i = 0, numlabels; l = g_new(colorLabels, 1); l->format = format; + if (zonep == without_zone || zonep == with_zone) { + l->zonep = zonep; + } else { + printf("color_labels_new: odd zonep %d\n", zonep); + l->zonep = with_zone; + } + + numlabels = (zonep == with_zone ? 5 : 3); if (label!=NULL){ lbl = gtk_label_new(label); gtk_misc_set_alignment(GTK_MISC(lbl), 1, 0.5); @@ -462,19 +472,109 @@ colorLabels *color_labels_new(GtkTable * GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0); i++; } - for (c=0; c<3; c++, i++) { + + /* 0-2 for RGB, 3 for value, 4 for zone */ + for (c=0; c<numlabels; c++, i++) { l->labels[c] = GTK_LABEL(gtk_label_new(NULL)); gtk_table_attach_defaults(table, GTK_WIDGET(l->labels[c]), x+i, x+i+1, y, y+1); + + if (c == 3) { +#if 0 + /* XXX insert an eventbox below the label */ + gtk_tooltips_set_tip(data->ToolTips, l->labels[c], + "Value (0-1)", NULL); +#else + (void) data; +#endif + } + if (c == 4) { +#if 0 + gtk_tooltips_set_tip(data->ToolTips, l->labels[c], + "Zone (after Adams)", NULL); +#endif + } } return l; } +/* + * XXX This code doesn't belong here. We probably should be using + * something in lcms instead. The values being processed here should + * probably be in the output colorspace (or working?) rather than the + * display colorspace that I think they are in. + */ + +/* + * Convert sRGB pixel value to 0-1 space, intending to reprsent, + * absent contrast manipulation and color issues, luminance relative + * to an 18% grey card at 0.18. + */ +double pixel2value(double pixel) +{ + double pl = pixel / 255.0; + double r; + + if (pl <= 0.04045) + r = pl/12.92; + else + r = pow((pl + 0.055)/1.055, 2.4); + return r; +} + +/* + * Convert pixel triplets to aggregate luminance. + */ +double pixels2value(double r, double g, double b) +{ + double y; + + /* Convert sRGB to Y of XYZ. */ + y = + 0.212671 * pixel2value(r) + + 0.715160 * pixel2value(g) + + 0.072169 * pixel2value(b); + + return y; +} + +/* + * Return numeric zone representation from 0-1 luminance value. + * Unlike Adams, we use arabic for now. + */ +double +value2zone(double v) +{ + const double zoneV = 0.18; + double z_rel_V; + double zone; + + /* Convert to value relative to zone V value. */ + z_rel_V = v / zoneV; + + /* + * Convert to log-based value, with zone V 0. Do not use log2 as it + * is not specified by POSIX and thus not portable. + */ + zone = log(z_rel_V)/log(2.0); + + /* + * Move zone 5 to the proper place. The code would be faster with a + * zone 0 calculation, but this version has fewer unfamiliar magic + * constants. + */ + zone += 5.0; + + return zone; +} + void color_labels_set(colorLabels *l, double data[3]) { int c; char buf1[max_name], buf2[max_name]; - const char *colorName[] = {"red", "green", "blue"}; + /* Value black, zone purple, for no good reason. */ + const char *colorName[] = {"red", "green", "blue", "black", "purple"}; + double value, zone; for (c=0; c<3; c++) { switch (l->format) { @@ -491,6 +591,27 @@ void color_labels_set(colorLabels *l, do colorName[c], buf1); gtk_label_set_markup(l->labels[c], buf2); } + + /* If value/zone not requested, just return now. */ + if (l->zonep == without_zone) + return; + + /* Value */ + c = 3; + value = pixels2value(data[0], data[1], data[2]); + snprintf(buf1, max_name, "%0.3f", value); + snprintf(buf2, max_name, "<span foreground='%s'>%s</span>", + colorName[c], buf1); + gtk_label_set_markup(l->labels[c], buf2); + + /* Zone */ + c = 4; + zone = value2zone(value); + /* 2 decimal places may be excessive */ + snprintf(buf1, max_name, "%0.2f", zone); + snprintf(buf2, max_name, "<span foreground='%s'>%s</span>", + colorName[c], buf1); + gtk_label_set_markup(l->labels[c], buf2); } #ifdef HAVE_GTKIMAGEVIEW @@ -2319,7 +2440,7 @@ int ufraw_preview(ufraw_data *uf, int pl table = GTK_TABLE(table_with_frame(previewVBox, NULL, FALSE)); data->SpotLabels = color_labels_new(table, 0, 1, - _("Spot values:"), pixel_format); + _("Spot values:"), pixel_format, with_zone, data); data->SpotPatch = GTK_LABEL(gtk_label_new(NULL)); gtk_table_attach_defaults(table, GTK_WIDGET(data->SpotPatch), 6, 7, 1, 2); @@ -3062,11 +3183,11 @@ int ufraw_preview(ufraw_data *uf, int pl i = 2; data->AvrLabels = color_labels_new(table, 0, i++, _("Average:"), - pixel_format); + pixel_format, without_zone, data); data->DevLabels = color_labels_new(table, 0, i++, _("Std. deviation:"), - pixel_format); + pixel_format, without_zone, data); data->OverLabels = color_labels_new(table, 0, i, - _("Overexposed:"), percent_format); + _("Overexposed:"), percent_format, without_zone, data); toggle_button(table, 4, i, NULL, &CFG->overExp); button = gtk_button_new_with_label(_("Indicate")); gtk_table_attach(table, button, 6, 7, i, i+1, @@ -3077,7 +3198,7 @@ int ufraw_preview(ufraw_data *uf, int pl G_CALLBACK(render_preview_callback), (void *)render_default); i++; data->UnderLabels = color_labels_new(table, 0, i, _("Underexposed:"), - percent_format); + percent_format, without_zone, data); toggle_button(table, 4, i, NULL, &CFG->underExp); button = gtk_button_new_with_label(_("Indicate")); gtk_table_attach(table, button, 6, 7, i, i+1, |