void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_tonecurve_gui_data_t)); dt_iop_tonecurve_gui_data_t *c = (dt_iop_tonecurve_gui_data_t *)self->gui_data; dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)self->params; c->minmax_curve = dt_draw_curve_new(0.0, 1.0, CUBIC_SPLINE); for(int k=0; k<6; k++) (void)dt_draw_curve_add_point(c->minmax_curve, p->tonecurve_x[k], p->tonecurve_y[k]); c->mouse_x = c->mouse_y = -1.0; c->selected = -1; c->selected_offset = c->selected_y = c->selected_min = c->selected_max = 0.0; c->dragging = 0; c->x_move = -1; self->widget = GTK_WIDGET(gtk_vbox_new(FALSE, 5)); c->area = GTK_DRAWING_AREA(gtk_drawing_area_new()); GtkWidget *asp = gtk_aspect_frame_new(NULL, 0.5, 0.5, 1.0, TRUE); gtk_box_pack_start(GTK_BOX(self->widget), asp, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(asp), GTK_WIDGET(c->area)); // gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->area), TRUE, TRUE, 0); gtk_drawing_area_size(c->area, 258, 258); g_object_set (GTK_OBJECT(c->area), "tooltip-text", _("abscissa: input, ordinate: output \nworks on L channel"), (char *)NULL); gtk_widget_add_events(GTK_WIDGET(c->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect (G_OBJECT (c->area), "expose-event", G_CALLBACK (dt_iop_tonecurve_expose), self); g_signal_connect (G_OBJECT (c->area), "button-press-event", G_CALLBACK (dt_iop_tonecurve_button_press), self); g_signal_connect (G_OBJECT (c->area), "button-release-event", G_CALLBACK (dt_iop_tonecurve_button_release), self); g_signal_connect (G_OBJECT (c->area), "motion-notify-event", G_CALLBACK (dt_iop_tonecurve_motion_notify), self); g_signal_connect (G_OBJECT (c->area), "leave-notify-event", G_CALLBACK (dt_iop_tonecurve_leave_notify), self); }
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)malloc(sizeof(dt_iop_lowlight_data_t)); dt_iop_lowlight_params_t *default_params = (dt_iop_lowlight_params_t *)self->default_params; piece->data = (void *)d; d->curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM); (void)dt_draw_curve_add_point(d->curve, default_params->transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, default_params->transition_y[DT_IOP_LOWLIGHT_BANDS-2]); for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++) (void)dt_draw_curve_add_point(d->curve, default_params->transition_x[k], default_params->transition_y[k]); (void)dt_draw_curve_add_point(d->curve, default_params->transition_x[1]+1.0, default_params->transition_y[1]); }
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { // create part of the gegl pipeline dt_iop_tonecurve_data_t *d = (dt_iop_tonecurve_data_t *)malloc(sizeof(dt_iop_tonecurve_data_t)); dt_iop_tonecurve_params_t *default_params = (dt_iop_tonecurve_params_t *)self->default_params; piece->data = (void *)d; d->curve = dt_draw_curve_new(0.0, 1.0, CUBIC_SPLINE); for(int k=0; k<6; k++) (void)dt_draw_curve_add_point(d->curve, default_params->tonecurve_x[k], default_params->tonecurve_y[k]); #ifdef HAVE_GEGL piece->input = piece->output = gegl_node_new_child(pipe->gegl, "operation", "gegl:dt-contrast-curve", "sampling-points", 65535, "curve", d->curve, NULL); #else for(int k=0; k<0x10000; k++) d->table[k] = 100.0f*k/0x10000; // identity #endif }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_lowlight_gui_data_t)); dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data; dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)self->params; c->transition_curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM); (void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p->transition_y[DT_IOP_LOWLIGHT_BANDS-2]); for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++) (void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[k], p->transition_y[k]); (void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[1]+1.0, p->transition_y[1]); c->mouse_x = c->mouse_y = c->mouse_pick = -1.0; c->dragging = 0; c->x_move = -1; c->mouse_radius = 1.0/DT_IOP_LOWLIGHT_BANDS; self->widget = GTK_WIDGET(gtk_vbox_new(FALSE, DT_GUI_IOP_MODULE_CONTROL_SPACING)); c->area = GTK_DRAWING_AREA(gtk_drawing_area_new()); gtk_drawing_area_size(c->area, 195, 195); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->area),FALSE, FALSE, 0); gtk_widget_add_events(GTK_WIDGET(c->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect (G_OBJECT (c->area), "expose-event", G_CALLBACK (lowlight_expose), self); g_signal_connect (G_OBJECT (c->area), "button-press-event", G_CALLBACK (lowlight_button_press), self); g_signal_connect (G_OBJECT (c->area), "button-release-event", G_CALLBACK (lowlight_button_release), self); g_signal_connect (G_OBJECT (c->area), "motion-notify-event", G_CALLBACK (lowlight_motion_notify), self); g_signal_connect (G_OBJECT (c->area), "leave-notify-event", G_CALLBACK (lowlight_leave_notify), self); g_signal_connect (G_OBJECT (c->area), "scroll-event", G_CALLBACK (lowlight_scrolled), self); c->scale_blueness = DTGTK_SLIDER(dtgtk_slider_new_with_range(DARKTABLE_SLIDER_BAR,0.0, 100.0, 5.0, p->blueness, 2)); dtgtk_slider_set_default_value(c->scale_blueness, p->blueness); dtgtk_slider_set_label(c->scale_blueness,_("blue shift")); dtgtk_slider_set_unit(c->scale_blueness,"%"); dtgtk_slider_set_format_type(c->scale_blueness,DARKTABLE_SLIDER_FORMAT_PERCENT); g_object_set(G_OBJECT(c->scale_blueness), "tooltip-text", _("blueness in shadows"), (char *)NULL); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->scale_blueness), TRUE, TRUE, 5); g_signal_connect (G_OBJECT (c->scale_blueness), "value-changed", G_CALLBACK (blueness_callback), self); }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_basecurve_gui_data_t)); dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data; dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params; c->minmax_curve = dt_draw_curve_new(0.0, 1.0, p->basecurve_type[0]); c->minmax_curve_type = p->basecurve_type[0]; c->minmax_curve_nodes = p->basecurve_nodes[0]; for(int k=0; k<p->basecurve_nodes[0]; k++) (void)dt_draw_curve_add_point(c->minmax_curve, p->basecurve[0][k].x, p->basecurve[0][k].y); c->mouse_x = c->mouse_y = -1.0; c->selected = -1; c->loglogscale = 0; self->widget = gtk_vbox_new(FALSE, DT_BAUHAUS_SPACE); c->area = GTK_DRAWING_AREA(gtk_drawing_area_new()); g_object_set (GTK_OBJECT(c->area), "tooltip-text", _("abscissa: input, ordinate: output. works on RGB channels"), (char *)NULL); // GtkWidget *asp = gtk_aspect_frame_new(NULL, 0.5, 0.5, 1.0, TRUE); // gtk_box_pack_start(GTK_BOX(self->widget), asp, TRUE, TRUE, 0); // gtk_container_add(GTK_CONTAINER(asp), GTK_WIDGET(c->area)); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->area), TRUE, TRUE, 0); gtk_widget_set_size_request(GTK_WIDGET(c->area), 0, 258); c->scale = dt_bauhaus_combobox_new(self); dt_bauhaus_widget_set_label(c->scale, NULL, _("scale")); dt_bauhaus_combobox_add(c->scale, _("linear")); dt_bauhaus_combobox_add(c->scale, _("logarithmic")); g_object_set(c->scale, "tooltip-text", _("scale to use in the graph. use logarithmic scale for more precise control near the blacks"), (char *)NULL); gtk_box_pack_start(GTK_BOX(self->widget), c->scale, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (c->scale), "value-changed", G_CALLBACK (scale_callback), self); gtk_widget_add_events(GTK_WIDGET(c->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect (G_OBJECT (c->area), "expose-event", G_CALLBACK (dt_iop_basecurve_expose), self); g_signal_connect (G_OBJECT (c->area), "button-press-event", G_CALLBACK (dt_iop_basecurve_button_press), self); g_signal_connect (G_OBJECT (c->area), "motion-notify-event", G_CALLBACK (dt_iop_basecurve_motion_notify), self); g_signal_connect (G_OBJECT (c->area), "leave-notify-event", G_CALLBACK (dt_iop_basecurve_leave_notify), self); g_signal_connect (G_OBJECT (c->area), "enter-notify-event", G_CALLBACK (dt_iop_basecurve_enter_notify), self); g_signal_connect (G_OBJECT (c->area), "configure-event", G_CALLBACK (area_resized), self); g_signal_connect (G_OBJECT (c->area), "scroll-event", G_CALLBACK (scrolled), self); }
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_colorzones_data_t *d = (dt_iop_colorzones_data_t *)malloc(sizeof(dt_iop_colorzones_data_t)); dt_iop_colorzones_params_t *default_params = (dt_iop_colorzones_params_t *)self->default_params; piece->data = (void *)d; for(int ch=0; ch<3; ch++) { d->curve[ch] = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM); (void)dt_draw_curve_add_point(d->curve[ch], default_params->equalizer_x[ch][DT_IOP_COLORZONES_BANDS-2]-1.0, default_params->equalizer_y[ch][DT_IOP_COLORZONES_BANDS-2]); for(int k=0; k<DT_IOP_COLORZONES_BANDS; k++) (void)dt_draw_curve_add_point(d->curve[ch], default_params->equalizer_x[ch][k], default_params->equalizer_y[ch][k]); (void)dt_draw_curve_add_point(d->curve[ch], default_params->equalizer_x[ch][1]+1.0, default_params->equalizer_y[ch][1]); } d->channel = (dt_iop_colorzones_channel_t)default_params->channel; #ifdef HAVE_GEGL #error "gegl version not implemeted!" #endif }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_lowlight_gui_data_t)); dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data; dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)self->params; c->transition_curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM); (void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[DT_IOP_LOWLIGHT_BANDS - 2] - 1.0, p->transition_y[DT_IOP_LOWLIGHT_BANDS - 2]); for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++) (void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[k], p->transition_y[k]); (void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[1] + 1.0, p->transition_y[1]); c->mouse_x = c->mouse_y = c->mouse_pick = -1.0; c->dragging = 0; c->x_move = -1; c->mouse_radius = 1.0 / DT_IOP_LOWLIGHT_BANDS; self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE); c->area = GTK_DRAWING_AREA(dtgtk_drawing_area_new_with_aspect_ratio(0.75)); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->area), FALSE, FALSE, 0); gtk_widget_add_events(GTK_WIDGET(c->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK); g_signal_connect(G_OBJECT(c->area), "draw", G_CALLBACK(lowlight_draw), self); g_signal_connect(G_OBJECT(c->area), "button-press-event", G_CALLBACK(lowlight_button_press), self); g_signal_connect(G_OBJECT(c->area), "button-release-event", G_CALLBACK(lowlight_button_release), self); g_signal_connect(G_OBJECT(c->area), "motion-notify-event", G_CALLBACK(lowlight_motion_notify), self); g_signal_connect(G_OBJECT(c->area), "leave-notify-event", G_CALLBACK(lowlight_leave_notify), self); g_signal_connect(G_OBJECT(c->area), "scroll-event", G_CALLBACK(lowlight_scrolled), self); c->scale_blueness = dt_bauhaus_slider_new_with_range(self, 0.0, 100.0, 1.0, p->blueness, 2); dt_bauhaus_widget_set_label(c->scale_blueness, NULL, _("blue shift")); dt_bauhaus_slider_set_format(c->scale_blueness, "%0.2f%%"); gtk_widget_set_tooltip_text(c->scale_blueness, _("blueness in shadows")); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->scale_blueness), TRUE, TRUE, 5); g_signal_connect(G_OBJECT(c->scale_blueness), "value-changed", G_CALLBACK(blueness_callback), self); }
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { // create part of the gegl pipeline dt_iop_tonecurve_data_t *d = (dt_iop_tonecurve_data_t *)malloc(sizeof(dt_iop_tonecurve_data_t)); dt_iop_tonecurve_params_t *default_params = (dt_iop_tonecurve_params_t *)self->default_params; piece->data = (void *)d; d->autoscale_ab = 1; for(int ch=0; ch<ch_max; ch++) { d->curve[ch] = dt_draw_curve_new(0.0, 1.0, default_params->tonecurve_type[ch]); d->curve_nodes[ch] = default_params->tonecurve_nodes[ch]; d->curve_type[ch] = default_params->tonecurve_type[ch]; for(int k=0; k<default_params->tonecurve_nodes[ch]; k++) (void)dt_draw_curve_add_point(d->curve[ch], default_params->tonecurve[ch][k].x, default_params->tonecurve[ch][k].y); } for(int k=0; k<0x10000; k++) d->table[ch_L][k] = 100.0f*k/0x10000; // identity for L for(int k=0; k<0x10000; k++) d->table[ch_a][k] = 256.0f*k/0x10000 - 128.0f; // identity for a for(int k=0; k<0x10000; k++) d->table[ch_b][k] = 256.0f*k/0x10000 - 128.0f; // identity for b }
void commit_params (struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_tonecurve_data_t *d = (dt_iop_tonecurve_data_t *)(piece->data); dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)p1; for(int ch=0; ch<ch_max; ch++) { // take care of possible change of curve type or number of nodes (not yet implemented in UI) if(d->curve_type[ch] != p->tonecurve_type[ch] || d->curve_nodes[ch] != p->tonecurve_nodes[ch]) { dt_draw_curve_destroy(d->curve[ch]); d->curve[ch] = dt_draw_curve_new(0.0, 1.0, p->tonecurve_type[ch]); d->curve_nodes[ch] = p->tonecurve_nodes[ch]; d->curve_type[ch] = p->tonecurve_type[ch]; for(int k=0; k<p->tonecurve_nodes[ch]; k++) (void)dt_draw_curve_add_point(d->curve[ch], p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } else { for(int k=0; k<p->tonecurve_nodes[ch]; k++) dt_draw_curve_set_point(d->curve[ch], k, p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } dt_draw_curve_calc_values(d->curve[ch], 0.0f, 1.0f, 0x10000, NULL, d->table[ch]); } for(int k=0; k<0x10000; k++) d->table[ch_L][k] *= 100.0f; for(int k=0; k<0x10000; k++) d->table[ch_a][k] = d->table[ch_a][k]*256.0f - 128.0f; for(int k=0; k<0x10000; k++) d->table[ch_b][k] = d->table[ch_b][k]*256.0f - 128.0f; d->autoscale_ab = p->tonecurve_autoscale_ab; // now the extrapolation stuff (for L curve only): const float xm = p->tonecurve[ch_L][p->tonecurve_nodes[ch_L]-1].x; const float x[4] = {0.7f*xm, 0.8f*xm, 0.9f*xm, 1.0f*xm}; const float y[4] = {d->table[ch_L][CLAMP((int)(x[0]*0x10000ul), 0, 0xffff)], d->table[ch_L][CLAMP((int)(x[1]*0x10000ul), 0, 0xffff)], d->table[ch_L][CLAMP((int)(x[2]*0x10000ul), 0, 0xffff)], d->table[ch_L][CLAMP((int)(x[3]*0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x, y, 4, d->unbounded_coeffs); }
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_basecurve_data_t *d = (dt_iop_basecurve_data_t *)(piece->data); dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)p1; const int ch = 0; // take care of possible change of curve type or number of nodes (not yet implemented in UI) if(d->basecurve_type != p->basecurve_type[ch] || d->basecurve_nodes != p->basecurve_nodes[ch]) { if(d->curve) // catch initial init_pipe case dt_draw_curve_destroy(d->curve); d->curve = dt_draw_curve_new(0.0, 1.0, p->basecurve_type[ch]); d->basecurve_nodes = p->basecurve_nodes[ch]; d->basecurve_type = p->basecurve_type[ch]; for(int k = 0; k < p->basecurve_nodes[ch]; k++) { // printf("p->basecurve[%i][%i].x = %f;\n", ch, k, p->basecurve[ch][k].x); // printf("p->basecurve[%i][%i].y = %f;\n", ch, k, p->basecurve[ch][k].y); (void)dt_draw_curve_add_point(d->curve, p->basecurve[ch][k].x, p->basecurve[ch][k].y); } } else { for(int k = 0; k < p->basecurve_nodes[ch]; k++) dt_draw_curve_set_point(d->curve, k, p->basecurve[ch][k].x, p->basecurve[ch][k].y); } dt_draw_curve_calc_values(d->curve, 0.0f, 1.0f, 0x10000, NULL, d->table); // now the extrapolation stuff: const float xm = p->basecurve[0][p->basecurve_nodes[0] - 1].x; const float x[4] = { 0.7f * xm, 0.8f * xm, 0.9f * xm, 1.0f * xm }; const float y[4] = { d->table[CLAMP((int)(x[0] * 0x10000ul), 0, 0xffff)], d->table[CLAMP((int)(x[1] * 0x10000ul), 0, 0xffff)], d->table[CLAMP((int)(x[2] * 0x10000ul), 0, 0xffff)], d->table[CLAMP((int)(x[3] * 0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x, y, 4, d->unbounded_coeffs); }
static gboolean dt_iop_tonecurve_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_tonecurve_gui_data_t *c = (dt_iop_tonecurve_gui_data_t *)self->gui_data; dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)self->params; dt_develop_t *dev = darktable.develop; const float color_labels_left[3][3] = { { 0.3f, 0.3f, 0.3f }, { 0.0f, 0.34f, 0.27f }, { 0.0f, 0.27f, 0.58f } }; const float color_labels_right[3][3] = {{ 0.3f, 0.3f, 0.3f }, { 0.53f, 0.08f, 0.28f}, { 0.81f, 0.66f, 0.0f } }; int ch = c->channel; int nodes = p->tonecurve_nodes[ch]; dt_iop_tonecurve_node_t *tonecurve = p->tonecurve[ch]; int autoscale_ab = p->tonecurve_autoscale_ab; if(c->minmax_curve_type[ch] != p->tonecurve_type[ch] || c->minmax_curve_nodes[ch] != p->tonecurve_nodes[ch]) { dt_draw_curve_destroy(c->minmax_curve[ch]); c->minmax_curve[ch] = dt_draw_curve_new(0.0, 1.0, p->tonecurve_type[ch]); c->minmax_curve_nodes[ch] = p->tonecurve_nodes[ch]; c->minmax_curve_type[ch] = p->tonecurve_type[ch]; for(int k=0; k<p->tonecurve_nodes[ch]; k++) (void)dt_draw_curve_add_point(c->minmax_curve[ch], p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } else { for(int k=0; k<p->tonecurve_nodes[ch]; k++) dt_draw_curve_set_point(c->minmax_curve[ch], k, p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } dt_draw_curve_t *minmax_curve = c->minmax_curve[ch]; dt_draw_curve_calc_values(minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_xs, c->draw_ys); const float xm = tonecurve[nodes-1].x; const float x[4] = {0.7f*xm, 0.8f*xm, 0.9f*xm, 1.0f*xm}; const float y[4] = {c->draw_ys[CLAMP((int)(x[0]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)], c->draw_ys[CLAMP((int)(x[1]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)], c->draw_ys[CLAMP((int)(x[2]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)], c->draw_ys[CLAMP((int)(x[3]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)] }; float unbounded_coeffs[3]; dt_iop_estimate_exp(x, y, 4, unbounded_coeffs); const int inset = DT_GUI_CURVE_EDITOR_INSET; int width = widget->allocation.width, height = widget->allocation.height; cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); // clear bg cairo_set_source_rgb (cr, .2, .2, .2); cairo_paint(cr); cairo_translate(cr, inset, inset); width -= 2*inset; height -= 2*inset; #if 0 // draw shadow around float alpha = 1.0f; for(int k=0; k<inset; k++) { cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } #else cairo_set_line_width(cr, 1.0); cairo_set_source_rgb (cr, .1, .1, .1); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_set_source_rgb (cr, .3, .3, .3); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); // draw color labels const int cells = 8; for(int j=0; j<cells; j++) { for(int i=0; i<cells; i++) { const float f = (cells-1-j+i)/(2.0f*cells-2.0f); cairo_set_source_rgba (cr, (1.0f-f)*color_labels_left[ch][0] + f*color_labels_right[ch][0], (1.0f-f)*color_labels_left[ch][1] + f*color_labels_right[ch][1], (1.0f-f)*color_labels_left[ch][2] + f*color_labels_right[ch][2], .5f); // blend over to make colors darker, so the overlay is more visible cairo_rectangle(cr, width*i/(float)cells, height*j/(float)cells, width/(float)cells, height/(float)cells); cairo_fill(cr); } } // draw grid cairo_set_line_width(cr, .4); cairo_set_source_rgb (cr, .1, .1, .1); if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM) dt_draw_waveform_lines(cr, 0, 0, width, height); else dt_draw_grid(cr, 4, 0, 0, width, height); // if autoscale_ab is on: do not display a and b curves if (autoscale_ab && ch != ch_L) goto finally; // draw nodes positions cairo_set_line_width(cr, 1.); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_translate(cr, 0, height); for(int k=0; k<nodes; k++) { cairo_arc(cr, tonecurve[k].x*width, -tonecurve[k].y*height, 3, 0, 2.*M_PI); cairo_stroke(cr); } // draw selected cursor cairo_set_line_width(cr, 1.); // draw histogram in background // only if module is enabled if (self->enabled) { float *hist, hist_max; float *raw_mean, *raw_min, *raw_max; float *raw_mean_output; float picker_mean[3], picker_min[3], picker_max[3]; char text[256]; raw_mean = self->picked_color; raw_min = self->picked_color_min; raw_max = self->picked_color_max; raw_mean_output = self->picked_output_color; hist = self->histogram; hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR?self->histogram_max[ch]:logf(1.0 + self->histogram_max[ch]); if(hist && hist_max > 0) { cairo_save(cr); cairo_scale(cr, width/63.0, -(height-5)/(float)hist_max); cairo_set_source_rgba(cr, .2, .2, .2, 0.5); dt_draw_histogram_8(cr, hist, ch, dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM?DT_DEV_HISTOGRAM_LOGARITHMIC:dev->histogram_type); // TODO: make draw handle waveform histograms cairo_restore(cr); } if(self->request_color_pick) { // the global live samples ... GSList *samples = darktable.lib->proxy.colorpicker.live_samples; dt_colorpicker_sample_t *sample = NULL; while(samples) { sample = samples->data; picker_scale(sample->picked_color_lab_mean, picker_mean); picker_scale(sample->picked_color_lab_min, picker_min); picker_scale(sample->picked_color_lab_max, picker_max); cairo_set_source_rgba(cr, 0.5, 0.7, 0.5, 0.15); cairo_rectangle(cr, width*picker_min[ch], 0, width*fmax(picker_max[ch]-picker_min[ch], 0.0f), -height); cairo_fill(cr); cairo_set_source_rgba(cr, 0.5, 0.7, 0.5, 0.5); cairo_move_to(cr, width*picker_mean[ch], 0); cairo_line_to(cr, width*picker_mean[ch], -height); cairo_stroke(cr); samples = g_slist_next(samples); } // ... and the local sample picker_scale(raw_mean, picker_mean); picker_scale(raw_min, picker_min); picker_scale(raw_max, picker_max); cairo_set_source_rgba(cr, 0.7, 0.5, 0.5, 0.33); cairo_rectangle(cr, width*picker_min[ch], 0, width*fmax(picker_max[ch]-picker_min[ch], 0.0f), -height); cairo_fill(cr); cairo_set_source_rgba(cr, 0.9, 0.7, 0.7, 0.5); cairo_move_to(cr, width*picker_mean[ch], 0); cairo_line_to(cr, width*picker_mean[ch], -height); cairo_stroke(cr); snprintf(text, 256, "%.1f → %.1f", raw_mean[ch], raw_mean_output[ch]); cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 0.06*height); cairo_move_to (cr, 0.02f*width, -0.94*height); cairo_show_text(cr, text); cairo_stroke(cr); } } if(c->selected >= 0) { cairo_set_source_rgb(cr, .9, .9, .9); cairo_arc(cr, tonecurve[c->selected].x*width, -tonecurve[c->selected].y*height, 4, 0, 2.*M_PI); cairo_stroke(cr); } // draw curve cairo_set_line_width(cr, 2.); cairo_set_source_rgb(cr, .9, .9, .9); // cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_move_to(cr, 0, -height*c->draw_ys[0]); for(int k=1; k<DT_IOP_TONECURVE_RES; k++) { const float xx = k/(DT_IOP_TONECURVE_RES-1.0); if(xx > xm) { const float yy = dt_iop_eval_exp(unbounded_coeffs, xx); cairo_line_to(cr, xx*width, - height*yy); } else { cairo_line_to(cr, xx*width, - height*c->draw_ys[k]); } } cairo_stroke(cr); finally: cairo_destroy(cr); cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface (cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return TRUE; }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_tonecurve_gui_data_t)); dt_iop_tonecurve_gui_data_t *c = (dt_iop_tonecurve_gui_data_t *)self->gui_data; dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)self->params; for (int ch=0; ch<ch_max; ch++) { c->minmax_curve[ch] = dt_draw_curve_new(0.0, 1.0, p->tonecurve_type[ch]); c->minmax_curve_nodes[ch] = p->tonecurve_nodes[ch]; c->minmax_curve_type[ch] = p->tonecurve_type[ch]; for(int k=0; k<p->tonecurve_nodes[ch]; k++) (void)dt_draw_curve_add_point(c->minmax_curve[ch], p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } c->channel = ch_L; c->mouse_x = c->mouse_y = -1.0; c->selected = -1; self->widget = gtk_vbox_new(FALSE, DT_BAUHAUS_SPACE); // tabs c->channel_tabs = GTK_NOTEBOOK(gtk_notebook_new()); gtk_notebook_append_page(GTK_NOTEBOOK(c->channel_tabs), GTK_WIDGET(gtk_hbox_new(FALSE,0)), gtk_label_new(_(" L "))); g_object_set(G_OBJECT(gtk_notebook_get_tab_label(c->channel_tabs, gtk_notebook_get_nth_page(c->channel_tabs, -1))), "tooltip-text", _("tonecurve for L channel"), NULL); gtk_notebook_append_page(GTK_NOTEBOOK(c->channel_tabs), GTK_WIDGET(gtk_hbox_new(FALSE,0)), gtk_label_new(_(" a "))); g_object_set(G_OBJECT(gtk_notebook_get_tab_label(c->channel_tabs, gtk_notebook_get_nth_page(c->channel_tabs, -1))), "tooltip-text", _("tonecurve for a channel"), NULL); gtk_notebook_append_page(GTK_NOTEBOOK(c->channel_tabs), GTK_WIDGET(gtk_hbox_new(FALSE,0)), gtk_label_new(_(" b "))); g_object_set(G_OBJECT(gtk_notebook_get_tab_label(c->channel_tabs, gtk_notebook_get_nth_page(c->channel_tabs, -1))), "tooltip-text", _("tonecurve for b channel"), NULL); gtk_widget_show_all(GTK_WIDGET(gtk_notebook_get_nth_page(c->channel_tabs, c->channel))); gtk_notebook_set_current_page(GTK_NOTEBOOK(c->channel_tabs), c->channel); g_object_set(G_OBJECT(c->channel_tabs), "homogeneous", TRUE, (char *)NULL); GtkWidget *tb = dtgtk_togglebutton_new(dtgtk_cairo_paint_colorpicker, CPF_STYLE_FLAT); g_object_set(G_OBJECT(tb), "tooltip-text", _("pick gui color from image"), (char *)NULL); GtkWidget *notebook = gtk_hbox_new(FALSE,0); gtk_box_pack_start(GTK_BOX(notebook), GTK_WIDGET(c->channel_tabs), FALSE, FALSE, 0); gtk_box_pack_end(GTK_BOX(notebook), GTK_WIDGET(tb), FALSE, FALSE, 0); GtkWidget *vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(self->widget), vbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(notebook), TRUE, TRUE, 0); g_signal_connect(G_OBJECT(c->channel_tabs), "switch_page", G_CALLBACK (tab_switch), self); c->area = GTK_DRAWING_AREA(gtk_drawing_area_new()); //GtkWidget *asp = gtk_aspect_frame_new(NULL, 0.5, 0.5, 1.0, FALSE);//TRUE); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(c->area), TRUE, TRUE, 0); // gtk_box_pack_start(GTK_BOX(vbox), asp, TRUE, TRUE, 0); // gtk_container_add(GTK_CONTAINER(asp), GTK_WIDGET(c->area)); gtk_drawing_area_size(c->area, 0, 258); g_object_set (GTK_OBJECT(c->area), "tooltip-text", _("double click to reset curve"), (char *)NULL); gtk_widget_add_events(GTK_WIDGET(c->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect (G_OBJECT (c->area), "expose-event", G_CALLBACK (dt_iop_tonecurve_expose), self); g_signal_connect (G_OBJECT (c->area), "button-press-event", G_CALLBACK (dt_iop_tonecurve_button_press), self); g_signal_connect (G_OBJECT (c->area), "motion-notify-event", G_CALLBACK (dt_iop_tonecurve_motion_notify), self); g_signal_connect (G_OBJECT (c->area), "leave-notify-event", G_CALLBACK (dt_iop_tonecurve_leave_notify), self); g_signal_connect (G_OBJECT (c->area), "enter-notify-event", G_CALLBACK (dt_iop_tonecurve_enter_notify), self); g_signal_connect (G_OBJECT (c->area), "configure-event", G_CALLBACK (area_resized), self); g_signal_connect (G_OBJECT(tb), "toggled", G_CALLBACK (pick_toggled), self); g_signal_connect (G_OBJECT (c->area), "scroll-event", G_CALLBACK (scrolled), self); c->autoscale_ab = dt_bauhaus_combobox_new(self); dt_bauhaus_widget_set_label(c->autoscale_ab, _("scale chroma")); dt_bauhaus_combobox_add(c->autoscale_ab, _("auto")); dt_bauhaus_combobox_add(c->autoscale_ab, _("manual")); gtk_box_pack_start(GTK_BOX(self->widget), c->autoscale_ab, TRUE, TRUE, 0); g_object_set (GTK_OBJECT(c->autoscale_ab), "tooltip-text", _("if set to auto, a and b curves have no effect and are not displayed. chroma values (a and b) of each pixel are then adjusted based on L curve data."), (char *)NULL); g_signal_connect(G_OBJECT(c->autoscale_ab), "value-changed", G_CALLBACK(autoscale_ab_callback), self); c->sizegroup = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL)); gtk_size_group_add_widget(c->sizegroup, GTK_WIDGET(c->area)); gtk_size_group_add_widget(c->sizegroup, GTK_WIDGET(c->channel_tabs)); }
static gboolean dt_iop_basecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data; dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params; int nodes = p->basecurve_nodes[0]; dt_iop_basecurve_node_t *basecurve = p->basecurve[0]; if(c->minmax_curve_type != p->basecurve_type[0] || c->minmax_curve_nodes != p->basecurve_nodes[0]) { dt_draw_curve_destroy(c->minmax_curve); c->minmax_curve = dt_draw_curve_new(0.0, 1.0, p->basecurve_type[0]); c->minmax_curve_nodes = p->basecurve_nodes[0]; c->minmax_curve_type = p->basecurve_type[0]; for(int k = 0; k < p->basecurve_nodes[0]; k++) (void)dt_draw_curve_add_point(c->minmax_curve, p->basecurve[0][k].x, p->basecurve[0][k].y); } else { for(int k = 0; k < p->basecurve_nodes[0]; k++) dt_draw_curve_set_point(c->minmax_curve, k, p->basecurve[0][k].x, p->basecurve[0][k].y); } dt_draw_curve_t *minmax_curve = c->minmax_curve; dt_draw_curve_calc_values(minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_xs, c->draw_ys); const float xm = basecurve[nodes - 1].x; const float x[4] = { 0.7f * xm, 0.8f * xm, 0.9f * xm, 1.0f * xm }; const float y[4] = { c->draw_ys[CLAMP((int)(x[0] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)], c->draw_ys[CLAMP((int)(x[1] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)], c->draw_ys[CLAMP((int)(x[2] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)], c->draw_ys[CLAMP((int)(x[3] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)] }; float unbounded_coeffs[3]; dt_iop_estimate_exp(x, y, 4, unbounded_coeffs); const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); // clear bg cairo_set_source_rgb(cr, .2, .2, .2); cairo_paint(cr); cairo_translate(cr, inset, inset); width -= 2 * inset; height -= 2 * inset; #if 0 // draw shadow around float alpha = 1.0f; for(int k=0; k<inset; k++) { cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } #else cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); cairo_set_source_rgb(cr, .1, .1, .1); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_set_source_rgb(cr, .3, .3, .3); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); cairo_translate(cr, 0, height); cairo_scale(cr, 1.0f, -1.0f); // draw grid cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.4)); cairo_set_source_rgb(cr, .1, .1, .1); if(c->loglogscale) dt_draw_loglog_grid(cr, 4, 0, 0, width, height, c->loglogscale); else dt_draw_grid(cr, 4, 0, 0, width, height); // draw nodes positions cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); for(int k = 0; k < nodes; k++) { const float x = to_log(basecurve[k].x, c->loglogscale), y = to_log(basecurve[k].y, c->loglogscale); cairo_arc(cr, x * width, y * height, DT_PIXEL_APPLY_DPI(3), 0, 2. * M_PI); cairo_stroke(cr); } // draw selected cursor cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); if(c->selected >= 0) { cairo_set_source_rgb(cr, .9, .9, .9); const float x = to_log(basecurve[c->selected].x, c->loglogscale), y = to_log(basecurve[c->selected].y, c->loglogscale); cairo_arc(cr, x * width, y * height, DT_PIXEL_APPLY_DPI(4), 0, 2. * M_PI); cairo_stroke(cr); } // draw curve cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.)); cairo_set_source_rgb(cr, .9, .9, .9); // cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_move_to(cr, 0, height * to_log(c->draw_ys[0], c->loglogscale)); for(int k = 1; k < DT_IOP_TONECURVE_RES; k++) { const float xx = k / (DT_IOP_TONECURVE_RES - 1.0); if(xx > xm) { const float yy = dt_iop_eval_exp(unbounded_coeffs, xx); const float x = to_log(xx, c->loglogscale), y = to_log(yy, c->loglogscale); cairo_line_to(cr, x * width, height * y); } else { const float yy = c->draw_ys[k]; const float x = to_log(xx, c->loglogscale), y = to_log(yy, c->loglogscale); cairo_line_to(cr, x * width, height * y); } } cairo_stroke(cr); cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_tonecurve_data_t *d = (dt_iop_tonecurve_data_t *)(piece->data); dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)p1; if(pipe->type == DT_DEV_PIXELPIPE_PREVIEW) piece->request_histogram |= (DT_REQUEST_ON); else piece->request_histogram &= ~(DT_REQUEST_ON); for(int ch = 0; ch < ch_max; ch++) { // take care of possible change of curve type or number of nodes (not yet implemented in UI) if(d->curve_type[ch] != p->tonecurve_type[ch] || d->curve_nodes[ch] != p->tonecurve_nodes[ch]) { dt_draw_curve_destroy(d->curve[ch]); d->curve[ch] = dt_draw_curve_new(0.0, 1.0, p->tonecurve_type[ch]); d->curve_nodes[ch] = p->tonecurve_nodes[ch]; d->curve_type[ch] = p->tonecurve_type[ch]; for(int k = 0; k < p->tonecurve_nodes[ch]; k++) (void)dt_draw_curve_add_point(d->curve[ch], p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } else { for(int k = 0; k < p->tonecurve_nodes[ch]; k++) dt_draw_curve_set_point(d->curve[ch], k, p->tonecurve[ch][k].x, p->tonecurve[ch][k].y); } dt_draw_curve_calc_values(d->curve[ch], 0.0f, 1.0f, 0x10000, NULL, d->table[ch]); } for(int k = 0; k < 0x10000; k++) d->table[ch_L][k] *= 100.0f; for(int k = 0; k < 0x10000; k++) d->table[ch_a][k] = d->table[ch_a][k] * 256.0f - 128.0f; for(int k = 0; k < 0x10000; k++) d->table[ch_b][k] = d->table[ch_b][k] * 256.0f - 128.0f; d->autoscale_ab = p->tonecurve_autoscale_ab; d->unbound_ab = p->tonecurve_unbound_ab; // extrapolation for L-curve (right hand side only): const float xm_L = p->tonecurve[ch_L][p->tonecurve_nodes[ch_L] - 1].x; const float x_L[4] = { 0.7f * xm_L, 0.8f * xm_L, 0.9f * xm_L, 1.0f * xm_L }; const float y_L[4] = { d->table[ch_L][CLAMP((int)(x_L[0] * 0x10000ul), 0, 0xffff)], d->table[ch_L][CLAMP((int)(x_L[1] * 0x10000ul), 0, 0xffff)], d->table[ch_L][CLAMP((int)(x_L[2] * 0x10000ul), 0, 0xffff)], d->table[ch_L][CLAMP((int)(x_L[3] * 0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x_L, y_L, 4, d->unbounded_coeffs_L); // extrapolation for a-curve right side: const float xm_ar = p->tonecurve[ch_a][p->tonecurve_nodes[ch_a] - 1].x; const float x_ar[4] = { 0.7f * xm_ar, 0.8f * xm_ar, 0.9f * xm_ar, 1.0f * xm_ar }; const float y_ar[4] = { d->table[ch_a][CLAMP((int)(x_ar[0] * 0x10000ul), 0, 0xffff)], d->table[ch_a][CLAMP((int)(x_ar[1] * 0x10000ul), 0, 0xffff)], d->table[ch_a][CLAMP((int)(x_ar[2] * 0x10000ul), 0, 0xffff)], d->table[ch_a][CLAMP((int)(x_ar[3] * 0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x_ar, y_ar, 4, d->unbounded_coeffs_ab); // extrapolation for a-curve left side (we need to mirror the x-axis): const float xm_al = 1.0f - p->tonecurve[ch_a][0].x; const float x_al[4] = { 0.7f * xm_al, 0.8f * xm_al, 0.9f * xm_al, 1.0f * xm_al }; const float y_al[4] = { d->table[ch_a][CLAMP((int)((1.0f - x_al[0]) * 0x10000ul), 0, 0xffff)], d->table[ch_a][CLAMP((int)((1.0f - x_al[1]) * 0x10000ul), 0, 0xffff)], d->table[ch_a][CLAMP((int)((1.0f - x_al[2]) * 0x10000ul), 0, 0xffff)], d->table[ch_a][CLAMP((int)((1.0f - x_al[3]) * 0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x_al, y_al, 4, d->unbounded_coeffs_ab + 3); // extrapolation for b-curve right side: const float xm_br = p->tonecurve[ch_b][p->tonecurve_nodes[ch_b] - 1].x; const float x_br[4] = { 0.7f * xm_br, 0.8f * xm_br, 0.9f * xm_br, 1.0f * xm_br }; const float y_br[4] = { d->table[ch_b][CLAMP((int)(x_br[0] * 0x10000ul), 0, 0xffff)], d->table[ch_b][CLAMP((int)(x_br[1] * 0x10000ul), 0, 0xffff)], d->table[ch_b][CLAMP((int)(x_br[2] * 0x10000ul), 0, 0xffff)], d->table[ch_b][CLAMP((int)(x_br[3] * 0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x_br, y_br, 4, d->unbounded_coeffs_ab + 6); // extrapolation for b-curve left side (we need to mirror the x-axis): const float xm_bl = 1.0f - p->tonecurve[ch_b][0].x; const float x_bl[4] = { 0.7f * xm_bl, 0.8f * xm_bl, 0.9f * xm_bl, 1.0f * xm_bl }; const float y_bl[4] = { d->table[ch_b][CLAMP((int)((1.0f - x_bl[0]) * 0x10000ul), 0, 0xffff)], d->table[ch_b][CLAMP((int)((1.0f - x_bl[1]) * 0x10000ul), 0, 0xffff)], d->table[ch_b][CLAMP((int)((1.0f - x_bl[2]) * 0x10000ul), 0, 0xffff)], d->table[ch_b][CLAMP((int)((1.0f - x_bl[3]) * 0x10000ul), 0, 0xffff)] }; dt_iop_estimate_exp(x_bl, y_bl, 4, d->unbounded_coeffs_ab + 9); }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_colorzones_gui_data_t)); dt_iop_colorzones_gui_data_t *c = (dt_iop_colorzones_gui_data_t *)self->gui_data; dt_iop_colorzones_params_t *p = (dt_iop_colorzones_params_t *)self->params; // c->channel = DT_IOP_COLORZONES_C; c->channel = dt_conf_get_int("plugins/darkroom/colorzones/gui_channel"); int ch = (int)c->channel; c->minmax_curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM); (void)dt_draw_curve_add_point(c->minmax_curve, p->equalizer_x[ch][DT_IOP_COLORZONES_BANDS-2]-1.0, p->equalizer_y[ch][DT_IOP_COLORZONES_BANDS-2]); for(int k=0; k<DT_IOP_COLORZONES_BANDS; k++) (void)dt_draw_curve_add_point(c->minmax_curve, p->equalizer_x[ch][k], p->equalizer_y[ch][k]); (void)dt_draw_curve_add_point(c->minmax_curve, p->equalizer_x[ch][1]+1.0, p->equalizer_y[ch][1]); c->mouse_x = c->mouse_y = c->mouse_pick = -1.0; c->dragging = 0; c->x_move = -1; c->mouse_radius = 1.0/DT_IOP_COLORZONES_BANDS; self->widget = GTK_WIDGET(gtk_vbox_new(FALSE, DT_GUI_IOP_MODULE_CONTROL_SPACING)); // select by which dimension GtkHBox *hbox = GTK_HBOX(gtk_hbox_new(FALSE, 5)); GtkWidget *label = gtk_label_new(_("select by")); gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); c->select_by = gtk_combo_box_new_text(); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_combo_box_append_text(GTK_COMBO_BOX(c->select_by), _("hue")); gtk_combo_box_append_text(GTK_COMBO_BOX(c->select_by), _("saturation")); gtk_combo_box_append_text(GTK_COMBO_BOX(c->select_by), _("lightness")); gtk_box_pack_start(GTK_BOX(hbox), c->select_by, TRUE, TRUE, 0); g_signal_connect (G_OBJECT (c->select_by), "changed", G_CALLBACK (select_by_changed), (gpointer)self); GtkWidget *tb = dtgtk_togglebutton_new(dtgtk_cairo_paint_colorpicker, CPF_STYLE_FLAT); g_object_set(G_OBJECT(tb), "tooltip-text", _("pick gui color from image"), (char *)NULL); g_signal_connect(G_OBJECT(tb), "toggled", G_CALLBACK(request_pick_toggled), self); gtk_box_pack_start(GTK_BOX(hbox), tb, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), FALSE, FALSE, 0); // tabs GtkVBox *vbox = GTK_VBOX(gtk_vbox_new(FALSE, 0));//DT_GUI_IOP_MODULE_CONTROL_SPACING)); c->channel_tabs = GTK_NOTEBOOK(gtk_notebook_new()); gtk_notebook_append_page(GTK_NOTEBOOK(c->channel_tabs), GTK_WIDGET(gtk_hbox_new(FALSE,0)), gtk_label_new(_("lightness"))); gtk_notebook_append_page(GTK_NOTEBOOK(c->channel_tabs), GTK_WIDGET(gtk_hbox_new(FALSE,0)), gtk_label_new(_("saturation"))); gtk_notebook_append_page(GTK_NOTEBOOK(c->channel_tabs), GTK_WIDGET(gtk_hbox_new(FALSE,0)), gtk_label_new(_("hue"))); gtk_widget_show_all(GTK_WIDGET(gtk_notebook_get_nth_page(c->channel_tabs, c->channel))); gtk_notebook_set_current_page(GTK_NOTEBOOK(c->channel_tabs), c->channel); g_object_set(G_OBJECT(c->channel_tabs), "homogeneous", TRUE, (char *)NULL); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(c->channel_tabs), FALSE, FALSE, 0); g_signal_connect(G_OBJECT(c->channel_tabs), "switch_page", G_CALLBACK (colorzones_tab_switch), self); // the nice graph c->area = GTK_DRAWING_AREA(gtk_drawing_area_new()); gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(c->area), TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(vbox), TRUE, TRUE, 5); gtk_drawing_area_size(c->area, 195, 195); gtk_widget_add_events(GTK_WIDGET(c->area), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); g_signal_connect (G_OBJECT (c->area), "expose-event", G_CALLBACK (colorzones_expose), self); g_signal_connect (G_OBJECT (c->area), "button-press-event", G_CALLBACK (colorzones_button_press), self); g_signal_connect (G_OBJECT (c->area), "button-release-event", G_CALLBACK (colorzones_button_release), self); g_signal_connect (G_OBJECT (c->area), "motion-notify-event", G_CALLBACK (colorzones_motion_notify), self); g_signal_connect (G_OBJECT (c->area), "leave-notify-event", G_CALLBACK (colorzones_leave_notify), self); g_signal_connect (G_OBJECT (c->area), "enter-notify-event", G_CALLBACK (colorzones_enter_notify), self); g_signal_connect (G_OBJECT (c->area), "scroll-event", G_CALLBACK (colorzones_scrolled), self); c->hsRGB = dt_colorspaces_create_srgb_profile(); c->hLab = dt_colorspaces_create_lab_profile(); c->xform = cmsCreateTransform(c->hLab, TYPE_Lab_DBL, c->hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL, 0); }