|
Packit Service |
2781ba |
/* This file is an image processing operation for GEGL
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2008 Hans Petter Jansson <hpj@copyleft.no>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
#include <glib/gi18n-lib.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_chant_int (red_bits, _("Red bits"), 1, 16, 16, _("Number of bits for red channel"))
|
|
Packit Service |
2781ba |
gegl_chant_int (green_bits, _("Green bits"), 1, 16, 16, _("Number of bits for green channel"))
|
|
Packit Service |
2781ba |
gegl_chant_int (blue_bits, _("Blue bits"), 1, 16, 16, _("Number of bits for blue channel"))
|
|
Packit Service |
2781ba |
gegl_chant_int (alpha_bits, _("Alpha bits"), 1, 16, 16, _("Number of bits for alpha channel"))
|
|
Packit Service |
2781ba |
gegl_chant_string (dither_type, _("Dither"), "none",
|
|
Packit Service |
2781ba |
_("Dithering strategy (none, random, random-covariant, bayer, floyd-steinberg)"))
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#else
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_TYPE_FILTER
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_C_FILE "color-reduction.c"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl-chant.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
prepare (GeglOperation *operation)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "input", babl_format ("RGBA u16"));
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "output", babl_format ("RGBA u16"));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
generate_channel_masks (guint *channel_bits, guint *channel_mask)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint i;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i = 0; i < 4; i++)
|
|
Packit Service |
2781ba |
channel_mask [i] = ~((1 << (16 - channel_bits [i])) - 1);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static guint
|
|
Packit Service |
2781ba |
quantize_value (guint value, guint n_bits, guint mask)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint i;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
value &= mask;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i = n_bits; i < 16; i += n_bits)
|
|
Packit Service |
2781ba |
value |= value >> i;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return value;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
process_floyd_steinberg (GeglBuffer *input,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
guint *channel_bits)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglRectangle line_rect;
|
|
Packit Service |
2781ba |
guint16 *line_buf;
|
|
Packit Service |
2781ba |
gdouble *error_buf [2];
|
|
Packit Service |
2781ba |
guint channel_mask [4];
|
|
Packit Service |
2781ba |
gint y;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_rect.x = result->x;
|
|
Packit Service |
2781ba |
line_rect.y = result->y;
|
|
Packit Service |
2781ba |
line_rect.width = result->width;
|
|
Packit Service |
2781ba |
line_rect.height = 1;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_buf = g_new (guint16, line_rect.width * 4);
|
|
Packit Service |
2781ba |
error_buf [0] = g_new0 (gdouble, line_rect.width * 4);
|
|
Packit Service |
2781ba |
error_buf [1] = g_new0 (gdouble, line_rect.width * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
generate_channel_masks (channel_bits, channel_mask);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (y = 0; y < result->height; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gdouble *error_buf_swap;
|
|
Packit Service |
2781ba |
gint step;
|
|
Packit Service |
2781ba |
gint start_x;
|
|
Packit Service |
2781ba |
gint end_x;
|
|
Packit Service |
2781ba |
gint x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Serpentine scanning; reverse direction every row */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (y & 1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
start_x = result->width - 1;
|
|
Packit Service |
2781ba |
end_x = -1;
|
|
Packit Service |
2781ba |
step = -1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
start_x = 0;
|
|
Packit Service |
2781ba |
end_x = result->width;
|
|
Packit Service |
2781ba |
step = 1;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Pull input row */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Process the row */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (x = start_x; x != end_x; x += step)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint16 *pixel = &line_buf [x * 4];
|
|
Packit Service |
2781ba |
guint ch;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (ch = 0; ch < 4; ch++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gdouble value;
|
|
Packit Service |
2781ba |
gdouble value_clamped;
|
|
Packit Service |
2781ba |
gdouble quantized;
|
|
Packit Service |
2781ba |
gdouble qerror;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
value = pixel [ch] + error_buf [0] [x * 4 + ch];
|
|
Packit Service |
2781ba |
value_clamped = CLAMP (value, 0.0, 65535.0);
|
|
Packit Service |
2781ba |
quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]);
|
|
Packit Service |
2781ba |
qerror = value - quantized;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
pixel [ch] = (guint16) quantized;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Distribute the error */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
error_buf [1] [x * 4 + ch] += qerror * 5.0 / 16.0; /* Down */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (x + step >= 0 && x + step < result->width)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
error_buf [0] [(x + step) * 4 + ch] += qerror * 6.0 / 16.0; /* Ahead */
|
|
Packit Service |
2781ba |
error_buf [1] [(x + step) * 4 + ch] += qerror * 1.0 / 16.0; /* Down, ahead */
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (x - step >= 0 && x - step < result->width)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
error_buf [1] [(x - step) * 4 + ch] += qerror * 3.0 / 16.0; /* Down, behind */
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Swap error accumulation rows */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
error_buf_swap = error_buf [0];
|
|
Packit Service |
2781ba |
error_buf [0] = error_buf [1];
|
|
Packit Service |
2781ba |
error_buf [1] = error_buf_swap;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Clear error buffer for next-plus-one line */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
memset (error_buf [1], 0, line_rect.width * 4 * sizeof (gdouble));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Push output row */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
line_rect.y++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_free (line_buf);
|
|
Packit Service |
2781ba |
g_free (error_buf [0]);
|
|
Packit Service |
2781ba |
g_free (error_buf [1]);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static const gdouble bayer_matrix_8x8 [] =
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
1, 49, 13, 61, 4, 52, 16, 64,
|
|
Packit Service |
2781ba |
33, 17, 45, 29, 36, 20, 48, 32,
|
|
Packit Service |
2781ba |
9, 57, 5, 53, 12, 60, 8, 56,
|
|
Packit Service |
2781ba |
41, 25, 37, 21, 44, 28, 40, 24,
|
|
Packit Service |
2781ba |
3, 51, 15, 63, 2, 50, 14, 62,
|
|
Packit Service |
2781ba |
35, 19, 47, 31, 34, 18, 46, 30,
|
|
Packit Service |
2781ba |
11, 59, 7, 55, 10, 58, 6, 54,
|
|
Packit Service |
2781ba |
43, 27, 39, 23, 42, 26, 38, 22
|
|
Packit Service |
2781ba |
};
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
process_bayer (GeglBuffer *input,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
guint *channel_bits)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglRectangle line_rect;
|
|
Packit Service |
2781ba |
guint16 *line_buf;
|
|
Packit Service |
2781ba |
guint channel_mask [4];
|
|
Packit Service |
2781ba |
guint y;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_rect.x = result->x;
|
|
Packit Service |
2781ba |
line_rect.y = result->y;
|
|
Packit Service |
2781ba |
line_rect.width = result->width;
|
|
Packit Service |
2781ba |
line_rect.height = 1;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_buf = g_new (guint16, line_rect.width * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
generate_channel_masks (channel_bits, channel_mask);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (y = 0; y < result->height; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (x = 0; x < result->width; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint16 *pixel = &line_buf [x * 4];
|
|
Packit Service |
2781ba |
guint ch;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (ch = 0; ch < 4; ch++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gdouble value;
|
|
Packit Service |
2781ba |
gdouble value_clamped;
|
|
Packit Service |
2781ba |
gdouble quantized;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
value = pixel [ch] + ((bayer_matrix_8x8 [(y % 8) * 8 + (x % 8)] - 32) * 65536.0 / 65.0) / (1 << (channel_bits [ch] - 1));
|
|
Packit Service |
2781ba |
value_clamped = CLAMP (value, 0.0, 65535.0);
|
|
Packit Service |
2781ba |
quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
pixel [ch] = (guint16) quantized;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
line_rect.y++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_free (line_buf);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
process_random_covariant (GeglBuffer *input,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
guint *channel_bits)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglRectangle line_rect;
|
|
Packit Service |
2781ba |
guint16 *line_buf;
|
|
Packit Service |
2781ba |
guint channel_mask [4];
|
|
Packit Service |
2781ba |
guint y;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_rect.x = result->x;
|
|
Packit Service |
2781ba |
line_rect.y = result->y;
|
|
Packit Service |
2781ba |
line_rect.width = result->width;
|
|
Packit Service |
2781ba |
line_rect.height = 1;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_buf = g_new (guint16, line_rect.width * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
generate_channel_masks (channel_bits, channel_mask);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (y = 0; y < result->height; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (x = 0; x < result->width; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint16 *pixel = &line_buf [x * 4];
|
|
Packit Service |
2781ba |
guint ch;
|
|
Packit Service |
2781ba |
gint r = g_random_int_range (-65536, 65536);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (ch = 0; ch < 4; ch++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gdouble value;
|
|
Packit Service |
2781ba |
gdouble value_clamped;
|
|
Packit Service |
2781ba |
gdouble quantized;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
value = pixel [ch] + (r / (1 << channel_bits [ch]));
|
|
Packit Service |
2781ba |
value_clamped = CLAMP (value, 0.0, 65535.0);
|
|
Packit Service |
2781ba |
quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
pixel [ch] = (guint16) quantized;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
line_rect.y++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_free (line_buf);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
process_random (GeglBuffer *input,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
guint *channel_bits)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglRectangle line_rect;
|
|
Packit Service |
2781ba |
guint16 *line_buf;
|
|
Packit Service |
2781ba |
guint channel_mask [4];
|
|
Packit Service |
2781ba |
guint y;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_rect.x = result->x;
|
|
Packit Service |
2781ba |
line_rect.y = result->y;
|
|
Packit Service |
2781ba |
line_rect.width = result->width;
|
|
Packit Service |
2781ba |
line_rect.height = 1;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_buf = g_new (guint16, line_rect.width * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
generate_channel_masks (channel_bits, channel_mask);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (y = 0; y < result->height; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (x = 0; x < result->width; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint16 *pixel = &line_buf [x * 4];
|
|
Packit Service |
2781ba |
guint ch;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (ch = 0; ch < 4; ch++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gdouble value;
|
|
Packit Service |
2781ba |
gdouble value_clamped;
|
|
Packit Service |
2781ba |
gdouble quantized;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
value = pixel [ch] + (g_random_int_range (-65536, 65536) / (1 << channel_bits [ch]));
|
|
Packit Service |
2781ba |
value_clamped = CLAMP (value, 0.0, 65535.0);
|
|
Packit Service |
2781ba |
quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
pixel [ch] = (guint16) quantized;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
line_rect.y++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_free (line_buf);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
process_no_dither (GeglBuffer *input,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
guint *channel_bits)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglRectangle line_rect;
|
|
Packit Service |
2781ba |
guint16 *line_buf;
|
|
Packit Service |
2781ba |
guint channel_mask [4];
|
|
Packit Service |
2781ba |
guint y;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_rect.x = result->x;
|
|
Packit Service |
2781ba |
line_rect.y = result->y;
|
|
Packit Service |
2781ba |
line_rect.width = result->width;
|
|
Packit Service |
2781ba |
line_rect.height = 1;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
line_buf = g_new (guint16, line_rect.width * 4);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
generate_channel_masks (channel_bits, channel_mask);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (y = 0; y < result->height; y++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint x;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (x = 0; x < result->width; x++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint16 *pixel = &line_buf [x * 4];
|
|
Packit Service |
2781ba |
guint ch;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (ch = 0; ch < 4; ch++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
pixel [ch] = quantize_value (pixel [ch], channel_bits [ch], channel_mask [ch]);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
line_rect.y++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_free (line_buf);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglRectangle
|
|
Packit Service |
2781ba |
get_required_for_output (GeglOperation *self,
|
|
Packit Service |
2781ba |
const gchar *input_pad,
|
|
Packit Service |
2781ba |
const GeglRectangle *roi)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return *gegl_operation_source_get_bounding_box (self, "input");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglRectangle
|
|
Packit Service |
2781ba |
get_cached_region (GeglOperation *self,
|
|
Packit Service |
2781ba |
const GeglRectangle *roi)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return *gegl_operation_source_get_bounding_box (self, "input");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
process (GeglOperation *operation,
|
|
Packit Service |
2781ba |
GeglBuffer *input,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
gint level)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit Service |
2781ba |
guint channel_bits [4];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
channel_bits [0] = o->red_bits;
|
|
Packit Service |
2781ba |
channel_bits [1] = o->green_bits;
|
|
Packit Service |
2781ba |
channel_bits [2] = o->blue_bits;
|
|
Packit Service |
2781ba |
channel_bits [3] = o->alpha_bits;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!o->dither_type)
|
|
Packit Service |
2781ba |
process_no_dither (input, output, result, channel_bits);
|
|
Packit Service |
2781ba |
else if (!strcasecmp (o->dither_type, "random"))
|
|
Packit Service |
2781ba |
process_random (input, output, result, channel_bits);
|
|
Packit Service |
2781ba |
else if (!strcasecmp (o->dither_type, "random-covariant"))
|
|
Packit Service |
2781ba |
process_random_covariant (input, output, result, channel_bits);
|
|
Packit Service |
2781ba |
else if (!strcasecmp (o->dither_type, "bayer"))
|
|
Packit Service |
2781ba |
process_bayer (input, output, result, channel_bits);
|
|
Packit Service |
2781ba |
else if (!strcasecmp (o->dither_type, "floyd-steinberg"))
|
|
Packit Service |
2781ba |
process_floyd_steinberg (input, output, result, channel_bits);
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
process_no_dither (input, output, result, channel_bits);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglOperationClass *operation_class;
|
|
Packit Service |
2781ba |
GeglOperationFilterClass *filter_class;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit Service |
2781ba |
filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
operation_class->prepare = prepare;
|
|
Packit Service |
2781ba |
operation_class->get_required_for_output = get_required_for_output;
|
|
Packit Service |
2781ba |
operation_class->get_cached_region = get_cached_region;
|
|
Packit Service |
2781ba |
filter_class->process = process;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_operation_class_set_keys (operation_class,
|
|
Packit Service |
2781ba |
"name" , "gegl:color-reduction",
|
|
Packit Service |
2781ba |
"categories" , "misc",
|
|
Packit Service |
2781ba |
"description" ,
|
|
Packit Service |
2781ba |
_("Reduces the number of bits per channel (colors and alpha), with optional dithering"),
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#endif
|