2
This file is part of darktable,
3
copyright (c) 2011 Rostyslav Pidgornyi
5
darktable is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
10
darktable is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with darktable. If not, see <http://www.gnu.org/licenses/>.
25
#include "common/colorspaces.h"
26
#include "common/darktable.h"
27
#include "common/debug.h"
28
#include "gui/histogram.h"
29
#include "develop/develop.h"
30
#include "control/control.h"
31
#include "control/conf.h"
34
#include "gui/presets.h"
35
#include "dtgtk/slider.h"
39
#define DT_IOP_LOWLIGHT_INSET 5
40
#define DT_IOP_LOWLIGHT_RES 64
41
#define DT_IOP_LOWLIGHT_BANDS 6
42
#define DT_IOP_LOWLIGHT_LUT_RES 0x10000
44
typedef struct dt_iop_lowlight_params_t
47
float transition_x[DT_IOP_LOWLIGHT_BANDS], transition_y[DT_IOP_LOWLIGHT_BANDS];
49
dt_iop_lowlight_params_t;
51
typedef struct dt_iop_lowlight_gui_data_t
53
dt_draw_curve_t *transition_curve; // curve for gui to draw
55
GtkDarktableSlider *scale_blueness;
57
double mouse_x, mouse_y, mouse_pick;
59
dt_iop_lowlight_params_t drag_params;
62
float draw_xs[DT_IOP_LOWLIGHT_RES], draw_ys[DT_IOP_LOWLIGHT_RES];
63
float draw_min_xs[DT_IOP_LOWLIGHT_RES], draw_min_ys[DT_IOP_LOWLIGHT_RES];
64
float draw_max_xs[DT_IOP_LOWLIGHT_RES], draw_max_ys[DT_IOP_LOWLIGHT_RES];
66
dt_iop_lowlight_gui_data_t;
68
typedef struct dt_iop_lowlight_data_t
71
dt_draw_curve_t *curve;
72
float lut[DT_IOP_LOWLIGHT_LUT_RES];
74
dt_iop_lowlight_data_t;
79
return _("lowlight vision");
84
return IOP_FLAGS_INCLUDE_IN_STYLES;
90
return IOP_GROUP_EFFECT;
95
lookup(const float *lut, const float i)
97
const int bin0 = MIN(0xffff, MAX(0, DT_IOP_LOWLIGHT_LUT_RES * i));
98
const int bin1 = MIN(0xffff, MAX(0, DT_IOP_LOWLIGHT_LUT_RES * i + 1));
99
const float f = DT_IOP_LOWLIGHT_LUT_RES * i - bin0;
100
return lut[bin1]*f + lut[bin0]*(1.-f);
104
process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
106
dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)(piece->data);
107
const int ch = piece->colors;
109
// empiric coefficient
110
const float c = 0.5f;
111
const float threshold = 0.01f;
113
// scotopic white, blue saturated
114
float Lab_sw[3] = { 100.0f , 0 , -d->blueness };
117
dt_Lab_to_XYZ(Lab_sw, XYZ_sw);
120
#pragma omp parallel for default(none) schedule(static) shared(roi_in, roi_out, d, i, o, XYZ_sw)
122
for(int k=0; k<roi_out->width*roi_out->height; k++)
124
float *in = (float *)i + ch*k;
125
float *out = (float *)o + ch*k;
126
float XYZ[3], XYZ_s[3];
130
dt_Lab_to_XYZ(in, XYZ);
132
// calculate scotopic luminanse
133
if (XYZ[0] > threshold)
136
V = XYZ[1] * ( 1.33f * ( 1.0f + (XYZ[1]+XYZ[2])/XYZ[0]) - 1.68f );
140
// low red flow, avoids "snow" on dark noisy areas
141
V = XYZ[1] * ( 1.33f * ( 1.0f + (XYZ[1]+XYZ[2])/threshold) - 1.68f );
144
// scale using empiric coefficient and fit inside limits
145
V = fminf(1.0f,fmaxf(0.0f,c*V));
147
// blending coefficient from curve
148
w = lookup(d->lut,in[0]/100.f);
150
XYZ_s[0] = V * XYZ_sw[0];
151
XYZ_s[1] = V * XYZ_sw[1];
152
XYZ_s[2] = V * XYZ_sw[2];
154
XYZ[0] = w * XYZ[0] + (1.0f - w) * XYZ_s[0];
155
XYZ[1] = w * XYZ[1] + (1.0f - w) * XYZ_s[1];
156
XYZ[2] = w * XYZ[2] + (1.0f - w) * XYZ_s[2];
158
dt_XYZ_to_Lab(XYZ,out);
162
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)
164
dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)(piece->data);
165
dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)p1;
166
dt_draw_curve_set_point(d->curve, 0, p->transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p->transition_y[0]);
167
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
168
dt_draw_curve_set_point(d->curve, k+1, p->transition_x[k], p->transition_y[k]);
169
dt_draw_curve_set_point(d->curve, DT_IOP_LOWLIGHT_BANDS+1, p->transition_x[1]+1.0, p->transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
170
dt_draw_curve_calc_values(d->curve, 0.0, 1.0, DT_IOP_LOWLIGHT_LUT_RES, NULL, d->lut);
171
d->blueness = p->blueness;
174
void init_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
176
dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)malloc(sizeof(dt_iop_lowlight_data_t));
177
dt_iop_lowlight_params_t *default_params = (dt_iop_lowlight_params_t *)self->default_params;
178
piece->data = (void *)d;
179
d->curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM);
180
(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]);
181
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
182
(void)dt_draw_curve_add_point(d->curve, default_params->transition_x[k], default_params->transition_y[k]);
183
(void)dt_draw_curve_add_point(d->curve, default_params->transition_x[1]+1.0, default_params->transition_y[1]);
186
void cleanup_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
188
// clean up everything again.
189
dt_iop_lowlight_data_t *d = (dt_iop_lowlight_data_t *)(piece->data);
190
dt_draw_curve_destroy(d->curve);
194
void gui_update(struct dt_iop_module_t *self)
196
dt_iop_lowlight_gui_data_t *g = (dt_iop_lowlight_gui_data_t *)self->gui_data;
197
dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)self->params;
198
dtgtk_slider_set_value(g->scale_blueness, p->blueness);
199
gtk_widget_queue_draw(self->widget);
202
void init(dt_iop_module_t *module)
204
module->params = malloc(sizeof(dt_iop_lowlight_params_t));
205
module->default_params = malloc(sizeof(dt_iop_lowlight_params_t));
206
module->default_enabled = 0; // we're a rather slow and rare op.
207
module->priority = 511; // module order created by iop_dependencies.py, do not edit!
208
module->params_size = sizeof(dt_iop_lowlight_params_t);
209
module->gui_data = NULL;
210
dt_iop_lowlight_params_t tmp;
211
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++) tmp.transition_x[k] = k/(DT_IOP_LOWLIGHT_BANDS-1.0);
212
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++) tmp.transition_y[k] = 0.5f;
214
memcpy(module->params, &tmp, sizeof(dt_iop_lowlight_params_t));
215
memcpy(module->default_params, &tmp, sizeof(dt_iop_lowlight_params_t));
218
void cleanup(dt_iop_module_t *module)
220
free(module->gui_data);
221
module->gui_data = NULL;
222
free(module->params);
223
module->params = NULL;
226
void init_presets (dt_iop_module_t *self)
228
dt_iop_lowlight_params_t p;
230
DT_DEBUG_SQLITE3_EXEC(darktable.db, "begin", NULL, NULL, NULL);
232
p.transition_x[0] = 0.000000;
233
p.transition_x[1] = 0.200000;
234
p.transition_x[2] = 0.400000;
235
p.transition_x[3] = 0.600000;
236
p.transition_x[4] = 0.800000;
237
p.transition_x[5] = 1.000000;
239
p.transition_y[0] = 1.000000;
240
p.transition_y[1] = 1.000000;
241
p.transition_y[2] = 1.000000;
242
p.transition_y[3] = 1.000000;
243
p.transition_y[4] = 1.000000;
244
p.transition_y[5] = 1.000000;
247
dt_gui_presets_add_generic(_("daylight"), self->op, &p, sizeof(p), 1);
249
p.transition_x[0] = 0.000000;
250
p.transition_x[1] = 0.200000;
251
p.transition_x[2] = 0.400000;
252
p.transition_x[3] = 0.600000;
253
p.transition_x[4] = 0.800000;
254
p.transition_x[5] = 1.000000;
256
p.transition_y[0] = 0.600000;
257
p.transition_y[1] = 0.800000;
258
p.transition_y[2] = 0.950000;
259
p.transition_y[3] = 0.980000;
260
p.transition_y[4] = 1.000000;
261
p.transition_y[5] = 1.000000;
264
dt_gui_presets_add_generic(_("indoor bright"), self->op, &p, sizeof(p), 1);
266
p.transition_x[0] = 0.000000;
267
p.transition_x[1] = 0.200000;
268
p.transition_x[2] = 0.400000;
269
p.transition_x[3] = 0.600000;
270
p.transition_x[4] = 0.800000;
271
p.transition_x[5] = 1.000000;
273
p.transition_y[0] = 0.300000;
274
p.transition_y[1] = 0.500000;
275
p.transition_y[2] = 0.700000;
276
p.transition_y[3] = 0.850000;
277
p.transition_y[4] = 0.970000;
278
p.transition_y[5] = 1.000000;
281
dt_gui_presets_add_generic(_("indoor dim"), self->op, &p, sizeof(p), 1);
283
p.transition_x[0] = 0.000000;
284
p.transition_x[1] = 0.200000;
285
p.transition_x[2] = 0.400000;
286
p.transition_x[3] = 0.600000;
287
p.transition_x[4] = 0.800000;
288
p.transition_x[5] = 1.000000;
290
p.transition_y[0] = 0.050000;
291
p.transition_y[1] = 0.200000;
292
p.transition_y[2] = 0.400000;
293
p.transition_y[3] = 0.700000;
294
p.transition_y[4] = 0.920000;
295
p.transition_y[5] = 1.000000;
298
dt_gui_presets_add_generic(_("indoor dark"), self->op, &p, sizeof(p), 1);
300
p.transition_x[0] = 0.000000;
301
p.transition_x[1] = 0.200000;
302
p.transition_x[2] = 0.400000;
303
p.transition_x[3] = 0.600000;
304
p.transition_x[4] = 0.800000;
305
p.transition_x[5] = 1.000000;
307
p.transition_y[0] = 0.070000;
308
p.transition_y[1] = 0.100000;
309
p.transition_y[2] = 0.180000;
310
p.transition_y[3] = 0.350000;
311
p.transition_y[4] = 0.750000;
312
p.transition_y[5] = 1.000000;
315
dt_gui_presets_add_generic(_("twilight"), self->op, &p, sizeof(p), 1);
317
p.transition_x[0] = 0.000000;
318
p.transition_x[1] = 0.200000;
319
p.transition_x[2] = 0.400000;
320
p.transition_x[3] = 0.600000;
321
p.transition_x[4] = 0.800000;
322
p.transition_x[5] = 1.000000;
324
p.transition_y[0] = 0.000000;
325
p.transition_y[1] = 0.450000;
326
p.transition_y[2] = 0.750000;
327
p.transition_y[3] = 0.930000;
328
p.transition_y[4] = 0.990000;
329
p.transition_y[5] = 1.000000;
332
dt_gui_presets_add_generic(_("night street lit"), self->op, &p, sizeof(p), 1);
334
p.transition_x[0] = 0.000000;
335
p.transition_x[1] = 0.200000;
336
p.transition_x[2] = 0.400000;
337
p.transition_x[3] = 0.600000;
338
p.transition_x[4] = 0.800000;
339
p.transition_x[5] = 1.000000;
341
p.transition_y[0] = 0.000000;
342
p.transition_y[1] = 0.150000;
343
p.transition_y[2] = 0.350000;
344
p.transition_y[3] = 0.800000;
345
p.transition_y[4] = 0.970000;
346
p.transition_y[5] = 1.000000;
349
dt_gui_presets_add_generic(_("night street"), self->op, &p, sizeof(p), 1);
351
p.transition_x[0] = 0.000000;
352
p.transition_x[1] = 0.150000;
353
p.transition_x[2] = 0.400000;
354
p.transition_x[3] = 0.600000;
355
p.transition_x[4] = 0.800000;
356
p.transition_x[5] = 1.000000;
358
p.transition_y[0] = 0.000000;
359
p.transition_y[1] = 0.020000;
360
p.transition_y[2] = 0.050000;
361
p.transition_y[3] = 0.200000;
362
p.transition_y[4] = 0.550000;
363
p.transition_y[5] = 1.000000;
366
dt_gui_presets_add_generic(_("night street dark"), self->op, &p, sizeof(p), 1);
368
p.transition_x[0] = 0.000000;
369
p.transition_x[1] = 0.200000;
370
p.transition_x[2] = 0.400000;
371
p.transition_x[3] = 0.600000;
372
p.transition_x[4] = 0.800000;
373
p.transition_x[5] = 1.000000;
375
p.transition_y[0] = 0.000000;
376
p.transition_y[1] = 0.000000;
377
p.transition_y[2] = 0.000000;
378
p.transition_y[3] = 0.000000;
379
p.transition_y[4] = 0.000000;
380
p.transition_y[5] = 0.000000;
384
dt_gui_presets_add_generic(_("night"), self->op, &p, sizeof(p), 1);
386
DT_DEBUG_SQLITE3_EXEC(darktable.db, "commit", NULL, NULL, NULL);
389
// fills in new parameters based on mouse position (in 0,1)
391
dt_iop_lowlight_get_params(dt_iop_lowlight_params_t *p, const double mouse_x, const double mouse_y, const float rad)
393
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
395
const float f = expf(-(mouse_x - p->transition_x[k])*(mouse_x - p->transition_x[k])/(rad*rad));
396
p->transition_y[k] = (1-f)*p->transition_y[k] + f*mouse_y;
401
lowlight_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
403
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
404
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
405
dt_iop_lowlight_params_t p = *(dt_iop_lowlight_params_t *)self->params;
407
dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
408
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++) dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
409
dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
411
const int inset = DT_IOP_LOWLIGHT_INSET;
412
int width = widget->allocation.width, height = widget->allocation.height;
413
cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
414
cairo_t *cr = cairo_create(cst);
416
cairo_set_source_rgb (cr, .2, .2, .2);
419
cairo_translate(cr, inset, inset);
423
cairo_set_line_width(cr, 1.0);
424
cairo_set_source_rgb (cr, .1, .1, .1);
425
cairo_rectangle(cr, 0, 0, width, height);
428
cairo_set_source_rgb (cr, .3, .3, .3);
429
cairo_rectangle(cr, 0, 0, width, height);
433
cairo_set_line_width(cr, .4);
434
cairo_set_source_rgb (cr, .1, .1, .1);
435
dt_draw_grid(cr, 8, 0, 0, width, height);
438
if(c->mouse_y > 0 || c->dragging)
440
// draw min/max curves:
441
dt_iop_lowlight_get_params(&p, c->mouse_x, 1., c->mouse_radius);
442
dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
443
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
444
dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
445
dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
446
dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_min_xs, c->draw_min_ys);
448
p = *(dt_iop_lowlight_params_t *)self->params;
449
dt_iop_lowlight_get_params(&p, c->mouse_x, .0, c->mouse_radius);
450
dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
451
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
452
dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
453
dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
454
dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_max_xs, c->draw_max_ys);
460
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
461
cairo_set_line_width(cr, 1.);
462
const float arrw = 7.0f;
463
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
465
cairo_move_to(cr, width*p.transition_x[k], height+inset-1);
466
cairo_rel_line_to(cr, -arrw*.5f, 0);
467
cairo_rel_line_to(cr, arrw*.5f, -arrw);
468
cairo_rel_line_to(cr, arrw*.5f, arrw);
469
cairo_close_path(cr);
470
if(c->x_move == k) cairo_fill(cr);
471
else cairo_stroke(cr);
474
// draw selected cursor
475
cairo_translate(cr, 0, height);
477
// cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
478
//cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
479
cairo_set_line_width(cr, 2.);
480
cairo_set_source_rgba(cr, .7, .7, .7, 1.0);
482
p = *(dt_iop_lowlight_params_t *)self->params;
483
dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
484
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
485
dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
486
dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
487
dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_xs, c->draw_ys);
488
cairo_move_to(cr, 0*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_ys[0]);
489
for(int k=1; k<DT_IOP_LOWLIGHT_RES; k++) cairo_line_to(cr, k*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_ys[k]);
492
// draw dots on knots
493
cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
494
cairo_set_line_width(cr, 1.);
495
for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
497
cairo_arc(cr, width*p.transition_x[k], - height*p.transition_y[k], 3.0, 0.0, 2.0*M_PI);
498
if(c->x_move == k) cairo_fill(cr);
499
else cairo_stroke(cr);
502
if(c->mouse_y > 0 || c->dragging)
504
// draw min/max, if selected
505
cairo_set_source_rgba(cr, .7, .7, .7, .6);
506
cairo_move_to(cr, 0, - height*c->draw_min_ys[0]);
507
for(int k=1; k<DT_IOP_LOWLIGHT_RES; k++) cairo_line_to(cr, k*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_min_ys[k]);
508
for(int k=DT_IOP_LOWLIGHT_RES-1; k>=0; k--) cairo_line_to(cr, k*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_max_ys[k]);
509
cairo_close_path(cr);
511
// draw mouse focus circle
512
cairo_set_source_rgba(cr, .9, .9, .9, .5);
513
const float pos = DT_IOP_LOWLIGHT_RES * c->mouse_x;
515
const float f = k - pos;
516
if(k >= DT_IOP_LOWLIGHT_RES-1) k = DT_IOP_LOWLIGHT_RES - 2;
517
float ht = -height*(f*c->draw_ys[k] + (1-f)*c->draw_ys[k+1]);
518
cairo_arc(cr, c->mouse_x*width, ht, c->mouse_radius*width, 0, 2.*M_PI);
524
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
527
cairo_text_extents_t ext;
528
cairo_set_source_rgb(cr, .1, .1, .1);
529
cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
530
cairo_set_font_size (cr, .06*height);
532
cairo_text_extents (cr, _("dark"), &ext);
533
cairo_move_to (cr, .02*width+ext.height, .5*(height+ext.width));
535
cairo_rotate (cr, -M_PI*.5f);
536
cairo_show_text(cr, _("dark"));
539
cairo_text_extents (cr, _("bright"), &ext);
540
cairo_move_to (cr, .98*width, .5*(height+ext.width));
542
cairo_rotate (cr, -M_PI*.5f);
543
cairo_show_text(cr, _("bright"));
546
cairo_text_extents (cr, _("day vision"), &ext);
547
cairo_move_to (cr, .5*(width-ext.width), .08*height);
548
cairo_show_text(cr, _("day vision"));
550
cairo_text_extents (cr, _("night vision"), &ext);
551
cairo_move_to (cr, .5*(width-ext.width), .97*height);
552
cairo_show_text(cr, _("night vision"));
556
cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget));
557
cairo_set_source_surface (cr_pixmap, cst, 0, 0);
558
cairo_paint(cr_pixmap);
559
cairo_destroy(cr_pixmap);
560
cairo_surface_destroy(cst);
565
lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
567
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
568
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
569
dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)self->params;
570
const int inset = DT_IOP_LOWLIGHT_INSET;
571
int height = widget->allocation.height - 2*inset, width = widget->allocation.width - 2*inset;
572
if(!c->dragging) c->mouse_x = CLAMP(event->x - inset, 0, width)/(float)width;
573
c->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height)/(float)height;
579
const float mx = CLAMP(event->x - inset, 0, width)/(float)width;
580
if(c->x_move > 0 && c->x_move < DT_IOP_LOWLIGHT_BANDS-1)
582
const float minx = p->transition_x[c->x_move-1]+0.001f;
583
const float maxx = p->transition_x[c->x_move+1]-0.001f;
584
p->transition_x[c->x_move] = fminf(maxx, fmaxf(minx, mx));
589
dt_iop_lowlight_get_params(p, c->mouse_x, c->mouse_y + c->mouse_pick, c->mouse_radius);
591
dt_dev_add_history_item(darktable.develop, self, TRUE);
593
else if(event->y > height)
596
float dist = fabsf(p->transition_x[0] - c->mouse_x);
597
for(int k=1; k<DT_IOP_LOWLIGHT_BANDS; k++)
599
float d2 = fabsf(p->transition_x[k] - c->mouse_x);
611
gtk_widget_queue_draw(widget);
613
gdk_window_get_pointer(event->window, &x, &y, NULL);
618
lowlight_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
620
if(event->button == 1)
622
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
623
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
624
c->drag_params = *(dt_iop_lowlight_params_t *)self->params;
625
const int inset = DT_IOP_LOWLIGHT_INSET;
626
int height = widget->allocation.height - 2*inset, width = widget->allocation.width - 2*inset;
627
c->mouse_pick = dt_draw_curve_calc_value(c->transition_curve, CLAMP(event->x - inset, 0, width)/(float)width);
628
c->mouse_pick -= 1.0 - CLAMP(event->y - inset, 0, height)/(float)height;
636
lowlight_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
638
if(event->button == 1)
640
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
641
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
649
lowlight_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
651
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
652
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
653
if(!c->dragging) c->mouse_x = c->mouse_y = -1.0;
654
gtk_widget_queue_draw(widget);
659
lowlight_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
661
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
662
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
663
if(event->direction == GDK_SCROLL_UP && c->mouse_radius > 0.2/DT_IOP_LOWLIGHT_BANDS) c->mouse_radius *= 0.9; //0.7;
664
if(event->direction == GDK_SCROLL_DOWN && c->mouse_radius < 1.0) c->mouse_radius *= (1.0/0.9); //1.42;
665
gtk_widget_queue_draw(widget);
670
blueness_callback (GtkDarktableSlider *slider, gpointer user_data)
672
dt_iop_module_t *self = (dt_iop_module_t *)user_data;
673
if(self->dt->gui->reset) return;
674
dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)self->params;
675
p->blueness = dtgtk_slider_get_value(slider);
676
dt_dev_add_history_item(darktable.develop, self, TRUE);
679
void gui_init(struct dt_iop_module_t *self)
681
self->gui_data = malloc(sizeof(dt_iop_lowlight_gui_data_t));
682
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
683
dt_iop_lowlight_params_t *p = (dt_iop_lowlight_params_t *)self->params;
685
c->transition_curve = dt_draw_curve_new(0.0, 1.0, CATMULL_ROM);
686
(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]);
687
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]);
688
(void)dt_draw_curve_add_point(c->transition_curve, p->transition_x[1]+1.0, p->transition_y[1]);
690
c->mouse_x = c->mouse_y = c->mouse_pick = -1.0;
693
c->mouse_radius = 1.0/DT_IOP_LOWLIGHT_BANDS;
695
self->widget = GTK_WIDGET(gtk_vbox_new(FALSE, DT_GUI_IOP_MODULE_CONTROL_SPACING));
697
c->area = GTK_DRAWING_AREA(gtk_drawing_area_new());
698
gtk_drawing_area_size(c->area, 195, 195);
700
gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->area),FALSE, FALSE, 0);
702
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);
703
g_signal_connect (G_OBJECT (c->area), "expose-event",
704
G_CALLBACK (lowlight_expose), self);
705
g_signal_connect (G_OBJECT (c->area), "button-press-event",
706
G_CALLBACK (lowlight_button_press), self);
707
g_signal_connect (G_OBJECT (c->area), "button-release-event",
708
G_CALLBACK (lowlight_button_release), self);
709
g_signal_connect (G_OBJECT (c->area), "motion-notify-event",
710
G_CALLBACK (lowlight_motion_notify), self);
711
g_signal_connect (G_OBJECT (c->area), "leave-notify-event",
712
G_CALLBACK (lowlight_leave_notify), self);
713
g_signal_connect (G_OBJECT (c->area), "scroll-event",
714
G_CALLBACK (lowlight_scrolled), self);
716
c->scale_blueness = DTGTK_SLIDER(dtgtk_slider_new_with_range(DARKTABLE_SLIDER_BAR,0.0, 100.0, 5.0, p->blueness, 2));
717
dtgtk_slider_set_default_value(c->scale_blueness, p->blueness);
718
dtgtk_slider_set_label(c->scale_blueness,_("blue shift"));
719
dtgtk_slider_set_unit(c->scale_blueness,"%");
720
dtgtk_slider_set_format_type(c->scale_blueness,DARKTABLE_SLIDER_FORMAT_PERCENT);
721
g_object_set(G_OBJECT(c->scale_blueness), "tooltip-text", _("blueness in shadows"), (char *)NULL);
723
gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(c->scale_blueness), TRUE, TRUE, 5);
725
g_signal_connect (G_OBJECT (c->scale_blueness), "value-changed",
726
G_CALLBACK (blueness_callback), self);
729
void gui_cleanup(struct dt_iop_module_t *self)
731
dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
732
dt_draw_curve_destroy(c->transition_curve);
733
free(self->gui_data);
734
self->gui_data = NULL;
737
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-space on;