81#define DT_COLORCORRECTION_INSET DT_PIXEL_APPLY_DPI(5)
82#define DT_COLORCORRECTION_MAX 40.
83#define PANEL_WIDTH 256.0f
108 return _(
"monochrome");
136 return dt_iop_set_description(self, _(
"quickly convert an image to black & white using a variable color filter"),
138 _(
"linear or non-linear, Lab, display-referred"),
139 _(
"non-linear, Lab"),
140 _(
"non-linear, Lab, display-referred"));
144 void *new_params,
const int new_version)
146 if(old_version == 1 && new_version == 2)
167 self->version(), &
p,
sizeof(
p), 1);
182static inline __attribute__((always_inline))
float color_filter(
const float ai,
const float bi,
const float a,
const float b,
const float size)
184 return dt_fast_expf(-
CLAMPS(((ai - a) * (ai - a) + (bi - b) * (bi - b)) / (2.0 *
size), 0.0f, 1.0f));
189 const float x =
CLAMPS(
L / 100.0f, 0.0f, 1.0f);
191 const float beta = 0.6f;
195 const float tmp = fabsf(
x / beta - 1.0f);
196 return 1.0f - tmp * tmp;
200 const float tmp1 = (1.0f -
x) / (1.0f - beta);
201 const float tmp2 = tmp1 * tmp1;
202 const float tmp3 = tmp2 * tmp1;
203 return 3.0f * tmp2 - 2.0f * tmp3;
213 const float sigma2 = (
d->size * 128.0) * (
d->size * 128.0f);
215 const size_t npixels = (size_t)roi_out->
height * roi_out->
width;
216 const float *
const restrict in = (
const float *)
i;
217 float *
const restrict
out = (
float *)o;
218 const float d_a =
d->a;
219 const float d_b =
d->b;
221 for(
int k = 0;
k < 4*npixels;
k += 4)
223 out[
k+0] = 100.0f * color_filter(in[
k+1], in[
k+2], d_a, d_b, sigma2);
231 const float sigma_s = 20.0f / scale;
232 const float detail = -1.0f;
241 const float highlights =
d->highlights;
243 for(
int k = 0;
k < 4*npixels;
k += 4)
246 const float t = tt + (1.0f - tt) * (1.0f - highlights);
247 out[
k] = (1.0f -
t) * in[
k] +
t *
out[
k] * (1.0f / 100.0f) * in[
k];
257 const float sigma_s = 20.0f / scale;
262 const int channels = 4;
264 const size_t basebuffer =
sizeof(float) * channels *
width *
height;
267 tiling->factor = 2.0f + (float)bilat_mem / basebuffer;
268 tiling->factor_cl = 3.0f + (float)bilat_mem / basebuffer;
287 d->highlights =
p->highlights;
320 GtkAllocation allocation;
321 gtk_widget_get_allocation(widget, &allocation);
322 int width = allocation.width,
height = allocation.height;
324 cairo_t *cr = cairo_create(cst);
326 cairo_set_source_rgb(cr, .2, .2, .2);
329 cairo_translate(cr, inset, inset);
330 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
337 cairo_translate(cr, 0,
height);
338 cairo_scale(cr, 1., -1.);
340 for(
int j = 0; j < cells; j++)
341 for(
int i = 0;
i < cells;
i++)
343 double rgb[3] = { 0.5, 0.5, 0.5 };
350 const float f = color_filter(
Lab.a,
Lab.b,
p->a,
p->b, 40 * 40 *
p->size *
p->size);
352 cmsDoTransform(
g->xform, &
Lab,
rgb, 1);
353 cairo_set_source_rgb(cr,
rgb[0],
rgb[1],
rgb[2]);
354 cairo_rectangle(cr,
width *
i / (
float)cells,
height * j / (
float)cells,
359 cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
360 cairo_set_source_rgb(cr, .7, .7, .7);
363 cairo_arc(cr,
x, y,
width * .22f *
p->size, 0, 2.0 *
M_PI);
367 cairo_set_source_surface(crf, cst, 0, 0);
369 cairo_surface_destroy(cst);
388 p->size = CLAMP((da + db)/128.0, .5, 3.0);
401 const float old_a =
p->a, old_b =
p->b;
403 GtkAllocation allocation;
404 gtk_widget_get_allocation(widget, &allocation);
405 int width = allocation.width - 2 * inset,
height = allocation.height - 2 * inset;
406 const float mouse_x = CLAMP(event->x - inset, 0,
width);
407 const float mouse_y = CLAMP(
height - 1 - event->y + inset, 0,
height);
412 gtk_widget_queue_draw(self->
gui->
widget);
419 if(event->button == 1)
425 if(event->type == GDK_2BUTTON_PRESS)
436 GtkAllocation allocation;
437 gtk_widget_get_allocation(widget, &allocation);
438 int width = allocation.width - 2 * inset,
height = allocation.height - 2 * inset;
439 const float mouse_x = CLAMP(event->x - inset, 0,
width);
440 const float mouse_y = CLAMP(
height - 1 - event->y + inset, 0,
height);
444 g_object_set(G_OBJECT(widget),
"has-tooltip",
FALSE, (gchar *)0);
446 gtk_widget_queue_draw(self->
gui->
widget);
454 if(event->button == 1)
461 g_object_set(G_OBJECT(widget),
"has-tooltip",
TRUE, (gchar *)0);
472 gtk_widget_queue_draw(self->
gui->
widget);
486 const float old_size =
p->size;
487 p->size = CLAMP(
p->size + delta_y * 0.1, 0.5f, 3.0f);
489 gtk_widget_queue_draw(widget);
505 gtk_widget_set_tooltip_text(GTK_WIDGET(
g->area), _(
"drag and scroll mouse wheel to adjust the virtual color filter"));
507 gtk_widget_add_events(GTK_WIDGET(
g->area), GDK_POINTER_MOTION_MASK
508 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
521 gtk_widget_set_tooltip_text(
g->highlights, _(
"how much to keep highlights"));
525 g->xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hsRGB, TYPE_RGB_DBL, INTENT_PERCEPTUAL,
532 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)
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_role_t role)
Resolve a profile identity to its registered entry.
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static dt_aligned_pixel_t rgb
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_dev_add_history_item(dev, module, enable, redraw)
GtkWidget * dtgtk_drawing_area_new_with_aspect_ratio(double aspect)
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 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
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
float *const restrict const size_t k
#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_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
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)
#define __OMP_PARALLEL_FOR__(...)
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
@ DT_PROFILE_ROLE_INPUT
Listed in the input-profile combo (colorin).
@ DT_PROFILE_ROLE_ANY
All four roles, in registration order.
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
cmsHPROFILE profile
the actual profile; NULL for the three category entries
struct dt_iop_module_t *void * data
dt_iop_buffer_type_t datatype
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
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.
#define __DT_CLONE_TARGETS__