static void process_random_covariant (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits) { GeglRectangle line_rect; guint16 *line_buf; guint channel_mask [4]; guint y; line_rect.x = result->x; line_rect.y = result->y; line_rect.width = result->width; line_rect.height = 1; line_buf = g_new (guint16, line_rect.width * 4); generate_channel_masks (channel_bits, channel_mask); for (y = 0; y < result->height; y++) { guint x; gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (x = 0; x < result->width; x++) { guint16 *pixel = &line_buf [x * 4]; guint ch; gint r = g_random_int_range (-65536, 65536); for (ch = 0; ch < 4; ch++) { gdouble value; gdouble value_clamped; gdouble quantized; value = pixel [ch] + (r / (1 << channel_bits [ch])); value_clamped = CLAMP (value, 0.0, 65535.0); quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]); pixel [ch] = (guint16) quantized; } } gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE); line_rect.y++; } g_free (line_buf); }
static void process_bayer (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits) { GeglRectangle line_rect; guint16 *line_buf; guint channel_mask [4]; guint y; line_rect.x = result->x; line_rect.y = result->y; line_rect.width = result->width; line_rect.height = 1; line_buf = g_new (guint16, line_rect.width * 4); generate_channel_masks (channel_bits, channel_mask); for (y = 0; y < result->height; y++) { guint x; gegl_buffer_get (input, 1.0, &line_rect, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE); for (x = 0; x < result->width; x++) { guint16 *pixel = &line_buf [x * 4]; guint ch; for (ch = 0; ch < 4; ch++) { gdouble value; gdouble value_clamped; gdouble quantized; value = pixel [ch] + ((bayer_matrix_8x8 [(y % 8) * 8 + (x % 8)] - 32) * 65536.0 / 65.0) / (1 << (channel_bits [ch] - 1)); value_clamped = CLAMP (value, 0.0, 65535.0); quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]); pixel [ch] = (guint16) quantized; } } gegl_buffer_set (output, &line_rect, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE); line_rect.y++; } g_free (line_buf); }
static void process_standard (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits, GeglRandom *rand, GeglDitherStrategy dither_strategy) { GeglBufferIterator *gi; guint channel_mask [4]; generate_channel_masks (channel_bits, channel_mask); gi = gegl_buffer_iterator_new (input, result, 0, babl_format ("R'G'B'A u16"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (gi, output, result, 0, babl_format ("R'G'B'A u16"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (gi)) { guint y; for (y = 0; y < gi->roi->height; y++) { switch (dither_strategy) { case GEGL_DITHER_NONE: process_row_no_dither (gi, channel_mask, channel_bits, y); break; case GEGL_DITHER_RANDOM: process_row_random (gi, channel_mask, channel_bits, y, rand); break; case GEGL_DITHER_RESILIENT: process_row_resilient (gi, channel_mask, channel_bits, y, rand); break; case GEGL_DITHER_RANDOM_COVARIANT: process_row_random_covariant (gi, channel_mask, channel_bits, y, rand); break; case GEGL_DITHER_BAYER: process_row_bayer (gi, channel_mask, channel_bits, y); break; case GEGL_DITHER_FLOYD_STEINBERG: /* Done separately */ break; default: process_row_no_dither (gi, channel_mask, channel_bits, y); } } } }
static void process_no_dither (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits) { GeglRectangle line_rect; guint16 *line_buf; guint channel_mask [4]; guint y; line_rect.x = result->x; line_rect.y = result->y; line_rect.width = result->width; line_rect.height = 1; line_buf = g_new (guint16, line_rect.width * 4); generate_channel_masks (channel_bits, channel_mask); for (y = 0; y < result->height; y++) { guint x; gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (x = 0; x < result->width; x++) { guint16 *pixel = &line_buf [x * 4]; guint ch; for (ch = 0; ch < 4; ch++) { pixel [ch] = quantize_value (pixel [ch], channel_bits [ch], channel_mask [ch]); } } gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE); line_rect.y++; } g_free (line_buf); }
static void process_floyd_steinberg (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits) { GeglRectangle line_rect; guint16 *line_buf; gdouble *error_buf [2]; guint channel_mask [4]; gint y; line_rect.x = result->x; line_rect.y = result->y; line_rect.width = result->width; line_rect.height = 1; line_buf = g_new (guint16, line_rect.width * 4); error_buf [0] = g_new0 (gdouble, line_rect.width * 4); error_buf [1] = g_new0 (gdouble, line_rect.width * 4); generate_channel_masks (channel_bits, channel_mask); for (y = 0; y < result->height; y++) { gdouble *error_buf_swap; gint step; gint start_x; gint end_x; gint x; /* Serpentine scanning; reverse direction every row */ if (y & 1) { start_x = result->width - 1; end_x = -1; step = -1; } else { start_x = 0; end_x = result->width; step = 1; } /* Pull input row */ gegl_buffer_get (input, &line_rect, 1.0, babl_format ("R'G'B'A u16"), line_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); /* Process the row */ for (x = start_x; x != end_x; x += step) { guint16 *pixel = &line_buf [x * 4]; guint ch; for (ch = 0; ch < 4; ch++) { gdouble value; gdouble value_clamped; gdouble quantized; gdouble qerror; value = pixel [ch] + error_buf [0] [x * 4 + ch]; value_clamped = CLAMP (value, 0.0, 65535.0); quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]); qerror = value - quantized; pixel [ch] = (guint16) quantized; /* Distribute the error */ error_buf [1] [x * 4 + ch] += qerror * 5.0 / 16.0; /* Down */ if (x + step >= 0 && x + step < result->width) { error_buf [0] [(x + step) * 4 + ch] += qerror * 6.0 / 16.0; /* Ahead */ error_buf [1] [(x + step) * 4 + ch] += qerror * 1.0 / 16.0; /* Down, ahead */ } if (x - step >= 0 && x - step < result->width) { error_buf [1] [(x - step) * 4 + ch] += qerror * 3.0 / 16.0; /* Down, behind */ } } } /* Swap error accumulation rows */ error_buf_swap = error_buf [0]; error_buf [0] = error_buf [1]; error_buf [1] = error_buf_swap; /* Clear error buffer for next-plus-one line */ memset (error_buf [1], 0, line_rect.width * 4 * sizeof (gdouble)); /* Push output row */ gegl_buffer_set (output, &line_rect, 0, babl_format ("R'G'B'A u16"), line_buf, GEGL_AUTO_ROWSTRIDE); line_rect.y++; } g_free (line_buf); g_free (error_buf [0]); g_free (error_buf [1]); }