77#define DT_COLORCORRECTION_INSET DT_PIXEL_APPLY_DPI(5)
78#define DT_COLORCORRECTION_MAX 40.
79#define PANEL_WIDTH 256.0f
104 return _(
"monochrome");
132 return dt_iop_set_description(self, _(
"quickly convert an image to black & white using a variable color filter"),
134 _(
"linear or non-linear, Lab, display-referred"),
135 _(
"non-linear, Lab"),
136 _(
"non-linear, Lab, display-referred"));
140 void *new_params,
const int new_version)
142 if(old_version == 1 && new_version == 2)
178static inline __attribute__((always_inline))
float color_filter(
const float ai,
const float bi,
const float a,
const float b,
const float size)
180 return dt_fast_expf(-
CLAMPS(((ai - a) * (ai - a) + (bi - b) * (bi - b)) / (2.0 *
size), 0.0f, 1.0f));
185 const float x =
CLAMPS(
L / 100.0f, 0.0f, 1.0f);
187 const float beta = 0.6f;
191 const float tmp = fabsf(
x / beta - 1.0f);
192 return 1.0f - tmp * tmp;
196 const float tmp1 = (1.0f -
x) / (1.0f - beta);
197 const float tmp2 = tmp1 * tmp1;
198 const float tmp3 = tmp2 * tmp1;
199 return 3.0f * tmp2 - 2.0f * tmp3;
209 const float sigma2 = (
d->size * 128.0) * (
d->size * 128.0f);
211 const size_t npixels = (size_t)roi_out->
height * roi_out->
width;
212 const float *
const restrict in = (
const float *)
i;
213 float *
const restrict
out = (
float *)o;
214 const float d_a =
d->a;
215 const float d_b =
d->b;
217 for(
int k = 0;
k < 4*npixels;
k += 4)
219 out[
k+0] = 100.0f * color_filter(in[
k+1], in[
k+2], d_a, d_b, sigma2);
227 const float sigma_s = 20.0f / scale;
228 const float detail = -1.0f;
237 const float highlights =
d->highlights;
239 for(
int k = 0;
k < 4*npixels;
k += 4)
242 const float t = tt + (1.0f - tt) * (1.0f - highlights);
243 out[
k] = (1.0f -
t) * in[
k] +
t *
out[
k] * (1.0f / 100.0f) * in[
k];
253 const float sigma_s = 20.0f / scale;
258 const int channels = 4;
260 const size_t basebuffer =
sizeof(float) * channels *
width *
height;
263 tiling->factor = 2.0f + (float)bilat_mem / basebuffer;
264 tiling->factor_cl = 3.0f + (float)bilat_mem / basebuffer;
283 d->highlights =
p->highlights;
316 GtkAllocation allocation;
317 gtk_widget_get_allocation(widget, &allocation);
318 int width = allocation.width,
height = allocation.height;
320 cairo_t *cr = cairo_create(cst);
322 cairo_set_source_rgb(cr, .2, .2, .2);
325 cairo_translate(cr, inset, inset);
326 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
333 cairo_translate(cr, 0,
height);
334 cairo_scale(cr, 1., -1.);
336 for(
int j = 0; j < cells; j++)
337 for(
int i = 0;
i < cells;
i++)
339 double rgb[3] = { 0.5, 0.5, 0.5 };
346 const float f = color_filter(
Lab.a,
Lab.b,
p->a,
p->b, 40 * 40 *
p->size *
p->size);
348 cmsDoTransform(
g->xform, &
Lab,
rgb, 1);
349 cairo_set_source_rgb(cr,
rgb[0],
rgb[1],
rgb[2]);
350 cairo_rectangle(cr,
width *
i / (
float)cells,
height * j / (
float)cells,
355 cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
356 cairo_set_source_rgb(cr, .7, .7, .7);
359 cairo_arc(cr,
x, y,
width * .22f *
p->size, 0, 2.0 *
M_PI);
363 cairo_set_source_surface(crf, cst, 0, 0);
365 cairo_surface_destroy(cst);
384 p->size = CLAMP((da + db)/128.0, .5, 3.0);
397 const float old_a =
p->a, old_b =
p->b;
399 GtkAllocation allocation;
400 gtk_widget_get_allocation(widget, &allocation);
401 int width = allocation.width - 2 * inset,
height = allocation.height - 2 * inset;
402 const float mouse_x = CLAMP(event->x - inset, 0,
width);
403 const float mouse_y = CLAMP(
height - 1 - event->y + inset, 0,
height);
408 gtk_widget_queue_draw(self->
widget);
415 if(event->button == 1)
421 if(event->type == GDK_2BUTTON_PRESS)
432 GtkAllocation allocation;
433 gtk_widget_get_allocation(widget, &allocation);
434 int width = allocation.width - 2 * inset,
height = allocation.height - 2 * inset;
435 const float mouse_x = CLAMP(event->x - inset, 0,
width);
436 const float mouse_y = CLAMP(
height - 1 - event->y + inset, 0,
height);
440 g_object_set(G_OBJECT(widget),
"has-tooltip",
FALSE, (gchar *)0);
442 gtk_widget_queue_draw(self->
widget);
450 if(event->button == 1)
457 g_object_set(G_OBJECT(widget),
"has-tooltip",
TRUE, (gchar *)0);
468 gtk_widget_queue_draw(self->
widget);
482 const float old_size =
p->size;
483 p->size = CLAMP(
p->size + delta_y * 0.1, 0.5f, 3.0f);
485 gtk_widget_queue_draw(widget);
500 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
g->area),
TRUE,
TRUE, 0);
501 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"drag and scroll mouse wheel to adjust the virtual color filter"));
503 gtk_widget_add_events(GTK_WIDGET(
g->area), GDK_POINTER_MOTION_MASK
504 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
517 gtk_widget_set_tooltip_text(
g->highlights, _(
"how much to keep highlights"));
521 g->xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL,
528 cmsDeleteTransform(
g->xform);
void dt_bilateral_free(dt_bilateral_t *b)
__DT_CLONE_TARGETS__ void dt_bilateral_splat(const dt_bilateral_t *b, const float *const in)
size_t dt_bilateral_memory_use(const int width, const int height, const float sigma_s, const float sigma_r)
dt_bilateral_t * dt_bilateral_init(const int width, const int height, const float sigma_s, const float sigma_r)
size_t dt_bilateral_singlebuffer_size(const int width, const int height, const float sigma_s, const float sigma_r)
__DT_CLONE_TARGETS__ void dt_bilateral_slice(const dt_bilateral_t *const b, const float *const in, float *out, const float detail)
void dt_bilateral_blur(const dt_bilateral_t *b)
@ DEVELOP_BLEND_CS_RGB_DISPLAY
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean keep)
GtkWidget * dt_color_picker_new(dt_iop_module_t *module, dt_iop_color_picker_kind_t kind, GtkWidget *w)
const dt_colorspaces_color_profile_t * dt_colorspaces_get_profile(dt_colorspaces_color_profile_type_t type, const char *filename, dt_colorspaces_profile_direction_t direction)
@ DT_PROFILE_DIRECTION_IN
@ DT_PROFILE_DIRECTION_ANY
static dt_aligned_pixel_t rgb
const dt_aligned_pixel_t f
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_control_queue_redraw_widget(GtkWidget *widget)
threadsafe request of redraw of specific widget. Use this function if you need to redraw a specific w...
static float envelope(const float xx)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_dev_add_history_item(dev, module, enable, redraw)
GtkWidget * dtgtk_drawing_area_new_with_aspect_ratio(double aspect)
gboolean dt_gui_get_scroll_unit_deltas(const GdkEventScroll *event, int *delta_x, int *delta_y)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
float *const restrict const size_t k
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)
const char ** description(struct dt_iop_module_t *self)
static gboolean dt_iop_monochrome_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static gboolean dt_iop_monochrome_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void gui_update(struct dt_iop_module_t *self)
Refresh GUI controls from current params and configuration.
void gui_init(struct dt_iop_module_t *self)
static gboolean dt_iop_monochrome_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
#define DT_COLORCORRECTION_INSET
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void input_format(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc)
void gui_cleanup(struct dt_iop_module_t *self)
void init_presets(dt_iop_module_so_t *self)
static gboolean dt_iop_monochrome_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const i, void *const o)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static gboolean dt_iop_monochrome_scrolled(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
static gboolean dt_iop_monochrome_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
int dt_opencl_avoid_atomics(const int devid)
struct _GtkWidget GtkWidget
struct dt_gui_gtk_t * gui
struct dt_develop_t * develop
struct dt_iop_module_t *void * data
dt_iop_buffer_type_t datatype
GModule *dt_dev_operation_t op
dt_iop_params_t * default_params
dt_iop_gui_data_t * gui_data
dt_aligned_pixel_t picked_color_min
dt_aligned_pixel_t picked_color_max
dt_aligned_pixel_t picked_color
Region of interest passed through the pixelpipe.