gegl r2221 - in trunk: . operations/workshop
- From: ok svn gnome org
- To: svn-commits-list gnome org
- Subject: gegl r2221 - in trunk: . operations/workshop
- Date: Wed, 23 Apr 2008 14:41:35 +0100 (BST)
Author: ok
Date: Wed Apr 23 13:41:35 2008
New Revision: 2221
URL: http://svn.gnome.org/viewvc/gegl?rev=2221&view=rev
Log:
* operations/workshop/color-reduction.c: added a color reduction
operation from Hans Petter Jansson <hpj at copyleft.no>
* AUTHORS: added Hans Petter Jansson.
Added:
trunk/operations/workshop/color-reduction.c
Modified:
trunk/AUTHORS
trunk/ChangeLog
Modified: trunk/AUTHORS
==============================================================================
--- trunk/AUTHORS (original)
+++ trunk/AUTHORS Wed Apr 23 13:41:35 2008
@@ -5,7 +5,8 @@
Sven Neumann, Michael Natterer, Ãyvind KolÃs, Philip Lafleur, Dominik Ernst,
Richard Kralovic, Kevin Cozens, Victor Bogado, Martin Nordholts, Geert
Jordaens, Michael Schumacher, John Marshall, Ãtienne Bersac, Mark Probst, HÃkon
-Hitland, Tor Lillqvist, Hans Breuer, Deji Akingunola and Bradley Broom.
+Hitland, Tor Lillqvist, Hans Breuer, Deji Akingunola and Bradley Broom,
+Hans Petter Jansson.
Documentation:
^^^^^^^^^^^^^^
Added: trunk/operations/workshop/color-reduction.c
==============================================================================
--- (empty file)
+++ trunk/operations/workshop/color-reduction.c Wed Apr 23 13:41:35 2008
@@ -0,0 +1,459 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2008 Hans Petter Jansson <hpj copyleft no>
+ */
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_int (red_bits, "Red bits", 1, 16, 16, "Number of bits for red channel")
+gegl_chant_int (green_bits, "Green bits", 1, 16, 16, "Number of bits for green channel")
+gegl_chant_int (blue_bits, "Blue bits", 1, 16, 16, "Number of bits for blue channel")
+gegl_chant_int (alpha_bits, "Alpha bits", 1, 16, 16, "Number of bits for alpha channel")
+gegl_chant_string (dither_type, "Dither", "none", "Dithering strategy (none, random, random-covariant, bayer, floyd-steinberg)")
+
+#else
+
+#define GEGL_CHANT_TYPE_FILTER
+#define GEGL_CHANT_C_FILE "color-reduction.c"
+
+#include "gegl-chant.h"
+
+static void
+prepare (GeglOperation *operation)
+{
+ gegl_operation_set_format (operation, "input", babl_format ("RGBA u16"));
+ gegl_operation_set_format (operation, "output", babl_format ("RGBA u16"));
+}
+
+static void
+generate_channel_masks (guint *channel_bits, guint *channel_mask)
+{
+ gint i;
+
+ for (i = 0; i < 4; i++)
+ channel_mask [i] = ~((1 << (16 - channel_bits [i])) - 1);
+}
+
+static guint
+quantize_value (guint value, guint n_bits, guint mask)
+{
+ gint i;
+
+ value &= mask;
+
+ for (i = n_bits; i < 16; i += n_bits)
+ value |= value >> i;
+
+ return value;
+}
+
+static void
+process_floyd_steinberg (GeglBuffer *input,
+ GeglBuffer *output,
+ guint *channel_bits)
+{
+ const GeglRectangle *input_rect;
+ GeglRectangle line_rect;
+ guint16 *line_buf;
+ gdouble *error_buf [2];
+ guint channel_mask [4];
+ gint y;
+
+ input_rect = gegl_buffer_get_extent (input);
+
+ line_rect.x = input_rect->x;
+ line_rect.y = input_rect->y;
+ line_rect.width = input_rect->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 < input_rect->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 = input_rect->width - 1;
+ end_x = -1;
+ step = -1;
+ }
+ else
+ {
+ start_x = 0;
+ end_x = input_rect->width;
+ step = 1;
+ }
+
+ /* Pull input row */
+
+ gegl_buffer_get (input, 1.0, &line_rect, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
+
+ /* 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 < input_rect->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 < input_rect->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, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
+ line_rect.y++;
+ }
+
+ g_free (line_buf);
+ g_free (error_buf [0]);
+ g_free (error_buf [1]);
+}
+
+static const gdouble bayer_matrix_8x8 [] =
+{
+ 1, 49, 13, 61, 4, 52, 16, 64,
+ 33, 17, 45, 29, 36, 20, 48, 32,
+ 9, 57, 5, 53, 12, 60, 8, 56,
+ 41, 25, 37, 21, 44, 28, 40, 24,
+ 3, 51, 15, 63, 2, 50, 14, 62,
+ 35, 19, 47, 31, 34, 18, 46, 30,
+ 11, 59, 7, 55, 10, 58, 6, 54,
+ 43, 27, 39, 23, 42, 26, 38, 22
+};
+
+static void
+process_bayer (GeglBuffer *input,
+ GeglBuffer *output,
+ guint *channel_bits)
+{
+ const GeglRectangle *input_rect;
+ GeglRectangle line_rect;
+ guint16 *line_buf;
+ guint channel_mask [4];
+ guint y;
+
+ input_rect = gegl_buffer_get_extent (input);
+
+ line_rect.x = input_rect->x;
+ line_rect.y = input_rect->y;
+ line_rect.width = input_rect->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 < input_rect->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 < input_rect->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_random_covariant (GeglBuffer *input,
+ GeglBuffer *output,
+ guint *channel_bits)
+{
+ const GeglRectangle *input_rect;
+ GeglRectangle line_rect;
+ guint16 *line_buf;
+ guint channel_mask [4];
+ guint y;
+
+ input_rect = gegl_buffer_get_extent (input);
+
+ line_rect.x = input_rect->x;
+ line_rect.y = input_rect->y;
+ line_rect.width = input_rect->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 < input_rect->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 < input_rect->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, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
+ line_rect.y++;
+ }
+
+ g_free (line_buf);
+}
+
+static void
+process_random (GeglBuffer *input,
+ GeglBuffer *output,
+ guint *channel_bits)
+{
+ const GeglRectangle *input_rect;
+ GeglRectangle line_rect;
+ guint16 *line_buf;
+ guint channel_mask [4];
+ guint y;
+
+ input_rect = gegl_buffer_get_extent (input);
+
+ line_rect.x = input_rect->x;
+ line_rect.y = input_rect->y;
+ line_rect.width = input_rect->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 < input_rect->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 < input_rect->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] + (g_random_int_range (-65536, 65536) / (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, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
+ line_rect.y++;
+ }
+
+ g_free (line_buf);
+}
+
+static void
+process_no_dither (GeglBuffer *input,
+ GeglBuffer *output,
+ guint *channel_bits)
+{
+ const GeglRectangle *input_rect;
+ GeglRectangle line_rect;
+ guint16 *line_buf;
+ guint channel_mask [4];
+ guint y;
+
+ input_rect = gegl_buffer_get_extent (input);
+
+ line_rect.x = input_rect->x;
+ line_rect.y = input_rect->y;
+ line_rect.width = input_rect->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 < input_rect->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 < input_rect->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, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE);
+ line_rect.y++;
+ }
+
+ g_free (line_buf);
+}
+
+static GeglRectangle
+get_required_for_output (GeglOperation *self,
+ const gchar *input_pad,
+ const GeglRectangle *roi)
+{
+ return *gegl_operation_source_get_bounding_box (self, "input");
+}
+
+static GeglRectangle
+get_cached_region (GeglOperation *self,
+ const GeglRectangle *roi)
+{
+ return *gegl_operation_source_get_bounding_box (self, "input");
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ guint channel_bits [4];
+
+ channel_bits [0] = o->red_bits;
+ channel_bits [1] = o->green_bits;
+ channel_bits [2] = o->blue_bits;
+ channel_bits [3] = o->alpha_bits;
+
+ if (!o->dither_type)
+ process_no_dither (input, output, channel_bits);
+ else if (!strcasecmp (o->dither_type, "random"))
+ process_random (input, output, channel_bits);
+ else if (!strcasecmp (o->dither_type, "random-covariant"))
+ process_random_covariant (input, output, channel_bits);
+ else if (!strcasecmp (o->dither_type, "bayer"))
+ process_bayer (input, output, channel_bits);
+ else if (!strcasecmp (o->dither_type, "floyd-steinberg"))
+ process_floyd_steinberg (input, output, channel_bits);
+ else
+ process_no_dither (input, output, channel_bits);
+
+ return TRUE;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+ GeglOperationClass *operation_class;
+ GeglOperationFilterClass *filter_class;
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+ filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
+
+ operation_class->prepare = prepare;
+ operation_class->get_required_for_output = get_required_for_output;
+ operation_class->get_cached_region = get_cached_region;
+ filter_class->process = process;
+
+ operation_class->name = "color-reduction";
+ operation_class->categories = "misc";
+ operation_class->description = "Reduces the number of bits per channel (colors and alpha), with optional dithering.";
+}
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]