120 return _(
"dithering");
125 return dt_iop_set_description(self, _(
"reduce banding and posterization effects in output JPEGs by adding random noise"),
127 _(
"non-linear, RGB, display-referred"),
128 _(
"non-linear, RGB"),
129 _(
"non-linear, RGB, display-referred"));
167 module->default_enabled = TRUE;
172static inline
float _quantize(const
float val, const
float f, const
float rf)
174 return rf * ceilf((val *
f) - 0.5);
184 return 0.30f * val[0] + 0.59f * val[1] + 0.11f * val[2];
188static inline
void nearest_color(
float *const restrict val,
float *const restrict err,
int graymode,
189 const
float f, const
float rf)
197 for(
int c = 0; c < 4; c++)
199 err[c] = val[c] -
new;
207 for(
int c = 0; c < 4; c++)
209 const float old = val[c];
217static inline void _diffuse_error(
float *
const restrict val,
const float *
const restrict err,
const float factor)
220 for(
int c = 0; c < 4; c++)
222 val[c] += err[c] *
factor;
226#if defined(__x86_64__) || defined(__i386__)
227static inline void _diffuse_error_sse(
float *val,
const __m128 err,
const float factor)
229 _mm_store_ps(val, _mm_load_ps(val) + (err * _mm_set1_ps(
factor)));
237 return (
x > 0.0f) ? ((
x < 1.0f) ?
x
247 for (
int c = 0; c < 4; c++)
252#define clipnan_pixel_sse clipnan_pixel
256 const float scale,
unsigned int *
const restrict
levels)
260 const int l1 = floorf(1.0f + dt_log2f(1.0f / scale));
316 __builtin_unreachable();
323#define RIGHT_WT (7.0f/16.0f)
324#define DOWNRIGHT_WT (1.0f/16.0f)
325#define DOWN_WT (5.0f/16.0f)
326#define DOWNLEFT_WT (3.0f/16.0f)
336 const float scale = roi_in->
scale;
338 const float *
const restrict in = (
const float *)ivoid;
339 float *
const restrict
out = (
float *)
ovoid;
342 int graymode = get_dither_parameters(data, pipe, piece, scale, &
levels);
351 const float rf = 1.0 /
f;
369 const size_t right = 4;
370 const size_t downleft = 4 * (
width-1);
371 const size_t down = 4 *
width;
372 const size_t downright = 4 * (
width+1);
374#define PROCESS_PIXEL_FULL(_pixel, inpix) \
376 float *const pixel_ = (_pixel); \
377 nearest_color(pixel_, err, graymode, f, rf); \
378 clipnan_pixel(pixel_ + downright,(inpix) + downright); \
379 _diffuse_error(pixel_ + right, err, RIGHT_WT); \
380 _diffuse_error(pixel_ + downleft, err, DOWNLEFT_WT); \
381 _diffuse_error(pixel_ + down, err, DOWN_WT); \
382 _diffuse_error(pixel_ + downright, err, DOWNRIGHT_WT); \
385#define PROCESS_PIXEL_LEFT(_pixel, inpix) \
387 float *const pixel_ = (_pixel); \
388 nearest_color(pixel_, err, graymode, f, rf); \
389 clipnan_pixel(pixel_ + down,(inpix) + down); \
390 clipnan_pixel(pixel_ + downright,(inpix) + downright); \
391 _diffuse_error(pixel_ + right, err, RIGHT_WT); \
392 _diffuse_error(pixel_ + down, err, DOWN_WT); \
393 _diffuse_error(pixel_ + downright, err, DOWNRIGHT_WT); \
396#define PROCESS_PIXEL_RIGHT(pixel) \
397 nearest_color(pixel, err, graymode, f, rf); \
398 _diffuse_error(pixel + downleft, err, DOWNLEFT_WT); \
399 _diffuse_error(pixel + down, err, DOWN_WT);
404 for (
int j = 0; j <
width; j++)
411 for(
int j = 0; j <
height - 1; j++)
413 const float *
const restrict inrow = in + (size_t)4 * j *
width;
414 float *
const restrict outrow =
out + (size_t)4 * j *
width;
431 float *
const restrict outrow =
out + (size_t)4 * (
height - 1) *
width;
436 float *
const restrict pixel = outrow + 4 *
i;
459 const float dither = powf(2.0f, data->
random.
damping / 10.0f);
467 for(
int j = 0; j <
height; j++)
469 const size_t k = (size_t)4 *
width * j;
470 const float *
const in = (
const float *)ivoid +
k;
472 tea_state[0] = j *
height;
476 float dith = dither *
tpdf(tea_state[0]);
478 for(
int c = 0; c < 4; c++)
513 cl_mem dev_work = NULL;
517 const int devid = pipe->
devid;
519 cl_int err = CL_SUCCESS;
524 const float dither = powf(2.0f,
d->random.damping / 10.0f);
533 if(err != CL_SUCCESS)
goto error;
549 if(w ==
g->dither_type)
557radius_callback (
GtkWidget *slider, gpointer user_data)
569range_callback (
GtkWidget *slider, gpointer user_data)
588 d->dither_type =
p->dither_type;
589 memcpy(&(
d->random.range), &(
p->random.range),
sizeof(
p->random.range));
590 d->random.radius =
p->random.radius;
591 d->random.damping =
p->random.damping;
615 const int program = 8;
654 gtk_widget_set_tooltip_text(
g->radius, _(
"radius for blurring step"));
666 gtk_widget_set_tooltip_text(
g->range, _(
"the gradient range where to apply random dither"));
667 g->range_label = gtk_label_new(_(
"gradient range"));
670 gtk_box_pack_start(GTK_BOX(rlabel), GTK_WIDGET(
g->range_label),
FALSE,
FALSE, 0);
675 gtk_widget_set_tooltip_text(
g->damping, _(
"damping level of random dither"));
680 gtk_box_pack_start(GTK_BOX(
g->random),
g->radius,
TRUE,
TRUE, 0);
681 gtk_box_pack_start(GTK_BOX(
g->random), rlabel,
TRUE,
TRUE, 0);
682 gtk_box_pack_start(GTK_BOX(
g->random),
g->range,
TRUE,
TRUE, 0);
692 g_signal_connect (G_OBJECT (
g->radius),
"value-changed",
693 G_CALLBACK (radius_callback), self);
694 g_signal_connect (G_OBJECT (
g->range),
"value-changed",
695 G_CALLBACK (range_callback), self);
static void error(char *msg)
int levels(struct dt_imageio_module_data_t *data)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
#define __OMP_SIMD__(...)
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...
static int dt_get_thread_num()
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL__(...)
#define __DT_CLONE_TARGETS__
#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_database_start_transaction(db)
#define dt_database_release_transaction(db)
#define dt_dev_add_history_item(dev, module, enable, redraw)
@ DT_DEV_PIXELPIPE_DISPLAY_MASK
static float _quantize(const float val, const float f, const float rf)
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)
void reload_defaults(dt_iop_module_t *module)
static void nearest_color(float *const restrict val, float *const restrict err, int graymode, const float f, const float rf)
static __DT_CLONE_TARGETS__ void process_random(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void clipnan_pixel(float *const restrict out, const float *const restrict in)
#define PROCESS_PIXEL_LEFT(_pixel, inpix)
void gui_update(struct dt_iop_module_t *self)
void gui_init(struct dt_iop_module_t *self)
static __DT_CLONE_TARGETS__ void process_floyd_steinberg(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
static float _rgb_to_gray(const float *const restrict val)
void cleanup_global(dt_iop_module_so_t *module)
static void _diffuse_error(float *const restrict val, const float *const restrict err, const float factor)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
#define PROCESS_PIXEL_FULL(_pixel, inpix)
void init_presets(dt_iop_module_so_t *self)
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
void init_global(dt_iop_module_so_t *module)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
static float clipnan(const float x)
#define PROCESS_PIXEL_RIGHT(pixel)
void dtgtk_gradient_slider_multivalue_set_value(GtkDarktableGradientSlider *gslider, gdouble value, gint pos)
gdouble dtgtk_gradient_slider_multivalue_get_value(GtkDarktableGradientSlider *gslider, gint pos)
GtkWidget * dtgtk_gradient_slider_multivalue_new(gint positions)
void dtgtk_gradient_slider_multivalue_set_marker(GtkDarktableGradientSlider *gslider, gint mark, gint pos)
#define DTGTK_GRADIENT_SLIDER(obj)
@ GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG
@ GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG
#define DT_GUI_BOX_SPACING
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)
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
float *const restrict const size_t k
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
int dt_opencl_create_kernel(const int prog, const char *name)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
void dt_opencl_release_mem_object(cl_mem mem)
@ DT_DEV_PIXELPIPE_EXPORT
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
struct _GtkWidget GtkWidget
int32_t num_openmp_threads
struct dt_gui_gtk_t * gui
const struct dt_database_t * db
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
struct dt_iop_module_t *void * data
dt_imageio_levels_t levels
dt_dev_pixelpipe_type_t type
dt_iop_dither_type_t dither_type
struct dt_iop_dither_data_t::@55 random
struct dt_iop_dither_params_t::@54 random
dt_iop_dither_type_t dither_type
GModule *dt_dev_operation_t op
dt_iop_global_data_t * data
dt_iop_gui_data_t * gui_data
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.
static float tpdf(unsigned int urandom)
static unsigned int * get_tea_state(unsigned int *const states, int threadnum)
static void free_tea_states(unsigned int *states)
static unsigned int * alloc_tea_states(size_t numthreads)
static void encrypt_tea(unsigned int *arg)