[gimp] app: implement optional dithering when converting to lower bit depth
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: implement optional dithering when converting to lower bit depth
- Date: Sat, 13 Oct 2012 19:48:27 +0000 (UTC)
commit 5dbcdef4777b91b1459fb92b9335110c611db300
Author: Michael Natterer <mitch gimp org>
Date: Sat Oct 13 21:46:56 2012 +0200
app: implement optional dithering when converting to lower bit depth
Add "layer_dither_type" and "mask_dither_type" to
GimpDrawable::convert_type(), pass around the dither type from the
dialog, and implement dithering using gegl:color-reduction.
app/core/gimpchannel.c | 63 ++++++++++++++++++++++++++++++++
app/core/gimpdrawable.c | 12 ++++++
app/core/gimpdrawable.h | 4 ++
app/core/gimpgrouplayer.c | 8 ++++-
app/core/gimpgrouplayerundo.c | 1 +
app/core/gimpimage-convert-precision.c | 5 ++-
app/core/gimpimage-convert-type.c | 1 +
app/core/gimplayer.c | 59 ++++++++++++++++++++++++++----
8 files changed, 144 insertions(+), 9 deletions(-)
---
diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c
index 9ad873b..85364d1 100644
--- a/app/core/gimpchannel.c
+++ b/app/core/gimpchannel.c
@@ -129,6 +129,13 @@ static void gimp_channel_to_selection (GimpItem *item,
gdouble feather_radius_x,
gdouble feather_radius_y);
+static void gimp_channel_convert_type (GimpDrawable *drawable,
+ GimpImage *dest_image,
+ GimpImageBaseType new_base_type,
+ GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
+ gboolean push_undo);
static void gimp_channel_invalidate_boundary (GimpDrawable *drawable);
static void gimp_channel_get_active_components (const GimpDrawable *drawable,
gboolean *active);
@@ -281,6 +288,7 @@ gimp_channel_class_init (GimpChannelClass *klass)
item_class->raise_failed = _("Channel cannot be raised higher.");
item_class->lower_failed = _("Channel cannot be lowered more.");
+ drawable_class->convert_type = gimp_channel_convert_type;
drawable_class->invalidate_boundary = gimp_channel_invalidate_boundary;
drawable_class->get_active_components = gimp_channel_get_active_components;
drawable_class->get_active_mask = gimp_channel_get_active_mask;
@@ -448,6 +456,7 @@ gimp_channel_convert (GimpItem *item,
{
gimp_drawable_convert_type (drawable, dest_image, GIMP_GRAY,
gimp_image_get_precision (dest_image),
+ 0, 0,
FALSE);
}
@@ -787,6 +796,60 @@ gimp_channel_to_selection (GimpItem *item,
}
static void
+gimp_channel_convert_type (GimpDrawable *drawable,
+ GimpImage *dest_image,
+ GimpImageBaseType new_base_type,
+ GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
+ gboolean push_undo)
+{
+ GeglBuffer *dest_buffer;
+ const Babl *format;
+
+ format = gimp_image_get_format (dest_image,
+ new_base_type,
+ new_precision,
+ gimp_drawable_has_alpha (drawable));
+
+ dest_buffer =
+ gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+ gimp_item_get_width (GIMP_ITEM (drawable)),
+ gimp_item_get_height (GIMP_ITEM (drawable))),
+ format);
+
+ if (mask_dither_type == 0)
+ {
+ gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
+ dest_buffer, NULL);
+ }
+ else
+ {
+ GeglNode *dither;
+ gint bits;
+
+ bits = (babl_format_get_bytes_per_pixel (format) * 8 /
+ babl_format_get_n_components (format));
+
+ dither = gegl_node_new_child (NULL,
+ "operation", "gegl:color-reduction",
+ "red-bits", bits,
+ "green-bits", bits,
+ "blue-bits", bits,
+ "alpha-bits", bits,
+ "dither-strategy", mask_dither_type,
+ NULL);
+
+ gimp_drawable_apply_operation_to_buffer (drawable, NULL, NULL,
+ dither, dest_buffer);
+ g_object_unref (dither);
+ }
+
+ gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
+ g_object_unref (dest_buffer);
+}
+
+static void
gimp_channel_invalidate_boundary (GimpDrawable *drawable)
{
GIMP_CHANNEL (drawable)->boundary_known = FALSE;
diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c
index 58cd405..5423fbf 100644
--- a/app/core/gimpdrawable.c
+++ b/app/core/gimpdrawable.c
@@ -132,6 +132,8 @@ static void gimp_drawable_real_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo);
static GeglBuffer * gimp_drawable_real_get_buffer (GimpDrawable *drawable);
@@ -670,11 +672,17 @@ gimp_drawable_real_estimate_memsize (const GimpDrawable *drawable,
return (gint64) babl_format_get_bytes_per_pixel (format) * width * height;
}
+/* FIXME: this default impl is currently unused because no subclass
+ * chins up. the goal is to handle the almost identical subclass code
+ * here again.
+ */
static void
gimp_drawable_real_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo)
{
GeglBuffer *dest_buffer;
@@ -1137,6 +1145,8 @@ gimp_drawable_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo)
{
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
@@ -1150,6 +1160,8 @@ gimp_drawable_convert_type (GimpDrawable *drawable,
GIMP_DRAWABLE_GET_CLASS (drawable)->convert_type (drawable, dest_image,
new_base_type,
new_precision,
+ layer_dither_type,
+ mask_dither_type,
push_undo);
}
diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h
index cd4c148..eb2236a 100644
--- a/app/core/gimpdrawable.h
+++ b/app/core/gimpdrawable.h
@@ -64,6 +64,8 @@ struct _GimpDrawableClass
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo);
void (* apply_buffer) (GimpDrawable *drawable,
GeglBuffer *buffer,
@@ -137,6 +139,8 @@ void gimp_drawable_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo);
void gimp_drawable_apply_buffer (GimpDrawable *drawable,
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index 1cfb5f3..70b0600 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -135,6 +135,8 @@ static void gimp_group_layer_convert_type (GimpDrawable *drawabl
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo);
static const Babl * gimp_group_layer_get_format (GimpProjectable *projectable);
@@ -847,6 +849,8 @@ gimp_group_layer_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo)
{
GimpGroupLayer *group = GIMP_GROUP_LAYER (drawable);
@@ -887,7 +891,9 @@ gimp_group_layer_convert_type (GimpDrawable *drawable,
new_precision != gimp_drawable_get_precision (GIMP_DRAWABLE (mask)))
{
gimp_drawable_convert_type (GIMP_DRAWABLE (mask), dest_image,
- GIMP_GRAY, new_precision, push_undo);
+ GIMP_GRAY, new_precision,
+ layer_dither_type, mask_dither_type,
+ push_undo);
}
}
diff --git a/app/core/gimpgrouplayerundo.c b/app/core/gimpgrouplayerundo.c
index 728ecfb..83f3fb2 100644
--- a/app/core/gimpgrouplayerundo.c
+++ b/app/core/gimpgrouplayerundo.c
@@ -128,6 +128,7 @@ gimp_group_layer_undo_pop (GimpUndo *undo,
gimp_item_get_image (GIMP_ITEM (group)),
group_layer_undo->prev_type,
group_layer_undo->prev_precision,
+ 0, 0,
FALSE);
group_layer_undo->prev_type = type;
diff --git a/app/core/gimpimage-convert-precision.c b/app/core/gimpimage-convert-precision.c
index 682f891..327d75c 100644
--- a/app/core/gimpimage-convert-precision.c
+++ b/app/core/gimpimage-convert-precision.c
@@ -104,7 +104,10 @@ gimp_image_convert_precision (GimpImage *image,
gimp_drawable_convert_type (drawable, image,
gimp_drawable_get_base_type (drawable),
- precision, TRUE);
+ precision,
+ layer_dither_type,
+ mask_dither_type,
+ TRUE);
if (progress)
gimp_progress_set_value (progress,
diff --git a/app/core/gimpimage-convert-type.c b/app/core/gimpimage-convert-type.c
index 0ef38aa..e7d814e 100644
--- a/app/core/gimpimage-convert-type.c
+++ b/app/core/gimpimage-convert-type.c
@@ -978,6 +978,7 @@ gimp_image_convert_type (GimpImage *image,
case GIMP_GRAY:
gimp_drawable_convert_type (GIMP_DRAWABLE (layer), image, new_type,
gimp_drawable_get_precision (GIMP_DRAWABLE (layer)),
+ 0, 0,
TRUE);
break;
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index bcf5113..652a1cb 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -159,6 +159,8 @@ static void gimp_layer_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo);
static void gimp_layer_invalidate_boundary (GimpDrawable *drawable);
static void gimp_layer_get_active_components (const GimpDrawable *drawable,
@@ -631,6 +633,7 @@ gimp_layer_convert (GimpItem *item,
{
gimp_drawable_convert_type (drawable, dest_image,
new_base_type, new_precision,
+ 0, 0,
FALSE);
}
@@ -950,21 +953,63 @@ gimp_layer_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
GimpImageBaseType new_base_type,
GimpPrecision new_precision,
+ gint layer_dither_type,
+ gint mask_dither_type,
gboolean push_undo)
{
- GimpLayer *layer = GIMP_LAYER (drawable);
+ GimpLayer *layer = GIMP_LAYER (drawable);
+ GeglBuffer *dest_buffer;
+ const Babl *format;
+
+ format = gimp_image_get_format (dest_image,
+ new_base_type,
+ new_precision,
+ gimp_drawable_has_alpha (drawable));
+
+ dest_buffer =
+ gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+ gimp_item_get_width (GIMP_ITEM (drawable)),
+ gimp_item_get_height (GIMP_ITEM (drawable))),
+ format);
+
+ if (layer_dither_type == 0)
+ {
+ gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
+ dest_buffer, NULL);
+ }
+ else
+ {
+ GeglNode *dither;
+ gint bits;
+
+ bits = (babl_format_get_bytes_per_pixel (format) * 8 /
+ babl_format_get_n_components (format));
+
+ dither = gegl_node_new_child (NULL,
+ "operation", "gegl:color-reduction",
+ "red-bits", bits,
+ "green-bits", bits,
+ "blue-bits", bits,
+ "alpha-bits", bits,
+ "dither-strategy", layer_dither_type,
+ NULL);
+
+ gimp_drawable_apply_operation_to_buffer (drawable, NULL, NULL,
+ dither, dest_buffer);
+ g_object_unref (dither);
+ }
+
+ gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
+ g_object_unref (dest_buffer);
if (layer->mask &&
new_precision != gimp_drawable_get_precision (GIMP_DRAWABLE (layer->mask)))
{
gimp_drawable_convert_type (GIMP_DRAWABLE (layer->mask), dest_image,
- GIMP_GRAY, new_precision, push_undo);
+ GIMP_GRAY, new_precision,
+ layer_dither_type, mask_dither_type,
+ push_undo);
}
-
- GIMP_DRAWABLE_CLASS (parent_class)->convert_type (drawable, dest_image,
- new_base_type,
- new_precision,
- push_undo);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]