Bugzilla – Attachment 209489 Details for
Bug 375616
Installer artwork dithering looks bad
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Forgot Password
color-reduction.c
color-reduction.c (text/plain), 12.67 KB, created by
Hans Petter Jansson
on 2008-04-22 06:18:37 UTC
(
hide
)
Description:
color-reduction.c
Filename:
MIME Type:
Creator:
Hans Petter Jansson
Created:
2008-04-22 06:18:37 UTC
Size:
12.67 KB
patch
obsolete
>/* 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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
Attachments on
bug 375616
:
207626
| 209489