[gimp] plugins: finish the port of decompose.c
- From: Téo Mazars <teom src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] plugins: finish the port of decompose.c
- Date: Sun, 30 Jun 2013 18:46:18 +0000 (UTC)
commit 385a6b60f3040eeeda6abc3525d70fc98e5addcc
Author: Téo Mazars <teo mazars ensimag fr>
Date: Sun Jun 30 20:28:38 2013 +0200
plugins: finish the port of decompose.c
- Add all missing decompositions needed for compat
- There are still some noticeable differences with the old plugin
(YCbCr mainly)
- decomposition of alpha is not coherent with gimp's current behaviour.
It still needs to be discussed.
- clamping is only here for compat, but it's probably not really needed.
- Others decompositions can now easily be added.
- compose.c remains unported
plug-ins/common/decompose.c | 266 +++++++++++++++++++++++++++++--------------
1 files changed, 179 insertions(+), 87 deletions(-)
---
diff --git a/plug-ins/common/decompose.c b/plug-ins/common/decompose.c
index f67412f..9217d3d 100644
--- a/plug-ins/common/decompose.c
+++ b/plug-ins/common/decompose.c
@@ -4,6 +4,9 @@
* Decompose plug-in (C) 1997 Peter Kirchgessner
* e-mail: peter kirchgessner net, WWW: http://www.kirchgessner.net
*
+ * Copyright 2013 Martijn van Beers <mail_dev martijn at>
+ * Copyright 2013 Téo Mazars <teo mazars ensimag fr>
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
@@ -18,10 +21,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * This filter decomposes RGB-images into several types of channels
- */
-
/* Lab colorspace support originally written by Alexey Dyachenko,
* merged into the officical plug-in by Sven Neumann.
*/
@@ -42,6 +41,52 @@
#define PLUG_IN_ROLE "gimp-decompose"
+/* Descrition of a component */
+typedef struct
+{
+ /* the babl_component names of the channels */
+ const gchar *babl_name;
+
+ /* Names of channels to extract */
+ const gchar *channel_name;
+
+ /* min and max */
+ const gdouble range_min;
+ const gdouble range_max;
+
+ /* Make the channel "correct" in Y' space */
+ const gboolean perceptual_channel;
+
+} COMPONENT;
+
+
+/* Maximum number of images/layers generated by an extraction */
+#define MAX_EXTRACT_IMAGES 4
+
+/* Description of an extraction */
+typedef struct
+{
+ const gchar *type; /* What to extract */
+ const gchar *model; /* the babl_model string to use */
+ const gboolean dialog; /* Dialog-Flag. Set it to TRUE if you want to appear
+ * this extract function within the dialog */
+ const gint num_images; /* Number of images to create */
+
+ const gboolean clamp; /* clamping values in [0.0, 1.0] */
+
+ /* the babl_component names of the channels */
+ const COMPONENT component[MAX_EXTRACT_IMAGES];
+
+} EXTRACT;
+
+typedef struct
+{
+ gchar extract_type[32];
+ gboolean as_layers;
+ gboolean use_registration;
+} DecoVals;
+
+
/* Declare local functions
*/
static void query (void);
@@ -74,80 +119,96 @@ static gint32 create_new_layer (gint32 image_ID,
static void transfer_registration_color (GeglBuffer *src,
GeglBuffer **dst,
gint count);
+static void cpn_affine_transform_clamp (GeglBuffer *buffer,
+ gdouble min,
+ gdouble max);
static void copy_n_components (GeglBuffer *src,
GeglBuffer **dst,
- const gchar *model,
- guint n,
- const gchar **components);
+ EXTRACT ext);
static void copy_one_component (GeglBuffer *src,
GeglBuffer *dst,
const char *model,
- const char *component);
+ const COMPONENT component,
+ gboolean clamp);
static gboolean decompose_dialog (void);
static gchar * generate_filename (guint32 image_ID,
guint colorspace,
guint channel);
-/* Maximum number of images/layers generated by an extraction */
-#define MAX_EXTRACT_IMAGES 4
+#define CPN_RGBA_R {"R", N_("red"), 0.0, 1.0, FALSE}
+#define CPN_RGBA_G {"G", N_("green"), 0.0, 1.0, FALSE}
+#define CPN_RGBA_B {"B", N_("blue"), 0.0, 1.0, FALSE}
+#define CPN_RGBA_A {"A", N_("alpha"), 0.0, 1.0, TRUE}
-/* Description of an extraction */
+#define CPN_HSV_H {"hue", N_("hue"), 0.0, 1.0, TRUE}
+#define CPN_HSV_S {"saturation", N_("saturation"), 0.0, 1.0, TRUE}
+#define CPN_HSV_V {"value", N_("value"), 0.0, 1.0, TRUE}
-typedef struct
-{
- const gchar *type; /* What to extract */
- const gchar *model ; /* the babl_model string to use */
- gboolean dialog; /* Dialog-Flag. Set it to TRUE if you want to appear
- * this extract function within the dialog */
- gint num_images; /* Number of images to create */
+#define CPN_HSL_H {"hue", N_("hue"), 0.0, 1.0, TRUE}
+#define CPN_HSL_S {"saturation", N_("saturation"), 0.0, 1.0, TRUE}
+#define CPN_HSL_L {"lightness", N_("value"), 0.0, 1.0, TRUE}
- /* the babl_component names of the channels */
- const gchar *component[MAX_EXTRACT_IMAGES];
+#define CPN_CMYK_C {"cyan", N_("cyan-k"), 0.0, 1.0, TRUE}
+#define CPN_CMYK_M {"magenta", N_("magenta-k"), 0.0, 1.0, TRUE}
+#define CPN_CMYK_Y {"yellow", N_("yellow-k"), 0.0, 1.0, TRUE}
+#define CPN_CMYK_K {"key", N_("black"), 0.0, 1.0, TRUE}
- /* Names of channels to extract */
- const gchar *channel_name[MAX_EXTRACT_IMAGES];
+#define CPN_CMY_C {"cyan", N_("cyan"), 0.0, 1.0, TRUE}
+#define CPN_CMY_M {"magenta", N_("magenta"), 0.0, 1.0, TRUE}
+#define CPN_CMY_Y {"yellow", N_("yellow"), 0.0, 1.0, TRUE}
-} EXTRACT;
+#define CPN_LAB_L {"CIE L", N_("L"), 0.0, 100.0, TRUE}
+#define CPN_LAB_A {"CIE a", N_("A"), -128.0, 127.0, TRUE}
+#define CPN_LAB_B {"CIE b", N_("B"), -128.0, 127.0, TRUE}
-/* FIXME: lots of missing conversions here */
-static EXTRACT extract[] =
+#define CPN_YCBCR_Y {"Y'", N_("luma-y470"), 0.0, 1.0, TRUE}
+#define CPN_YCBCR_CB {"Cb", N_("blueness-cb470"), -0.5, 0.5, TRUE}
+#define CPN_YCBCR_CR {"Cr", N_("redness-cr470"), -0.5, 0.5, TRUE}
+
+#define CPN_YCBCR709_Y {"Y'", N_("luma-y709"), 0.0, 1.0, TRUE}
+#define CPN_YCBCR709_CB {"Cb", N_("blueness-cb709"), -0.5, 0.5, TRUE}
+#define CPN_YCBCR709_CR {"Cr", N_("redness-cr709"), -0.5, 0.5, TRUE}
+
+
+static const EXTRACT extract[] =
{
- { N_("RGB"), "RGB", TRUE, 3, {"R", "G", "B"}, { N_("red"),
- N_("green"),
- N_("blue") } },
-
- { N_("Red"), "RGB", FALSE, 1, { "R" }, { N_("red") } },
- { N_("Green"), "RGB", FALSE, 1, { "G" }, { N_("green") } },
- { N_("Blue"), "RGB", FALSE, 1, { "B" }, { N_("blue") } },
- { N_("Alpha"), "RGBA", TRUE , 1, { "A" }, { N_("alpha") } },
-
- { N_("RGBA"), "RGBA", TRUE, 4, { "R", "G", "B", "A" }, { N_("red"),
- N_("green"),
- N_("blue"),
- N_("alpha") } },
-
- { N_("LAB"), "CIE Lab", FALSE, 3, {"CIE L", "CIE a", "CIE b"}, { N_("L"),
- N_("A"),
- N_("B") } },
-
- { N_("CMYK"), "CMYK", FALSE, 4, {"cyan", "magenta", "yellow", "key"}, { N_("cyan-k"),
- N_("magenta-k"),
- N_("yellow-k"),
- N_("black") } },
-
- { N_("HSVA"), "HSVA", FALSE, 4, {"hue", "saturation", "value", "alpha"}, { N_("hue"),
- N_("saturation"),
- N_("value")} }
+ { N_("RGB"), "RGB", TRUE, 3, FALSE, {CPN_RGBA_R, CPN_RGBA_G, CPN_RGBA_B} },
+ { N_("RGBA"), "RGBA", TRUE, 4, FALSE, {CPN_RGBA_R, CPN_RGBA_G, CPN_RGBA_B, CPN_RGBA_A} },
+ { N_("Red"), "RGB", FALSE, 1, FALSE, {CPN_RGBA_R} },
+ { N_("Green"), "RGB", FALSE, 1, FALSE, {CPN_RGBA_G} },
+ { N_("Blue"), "RGB", FALSE, 1, FALSE, {CPN_RGBA_B} },
+ { N_("Alpha"), "RGBA", TRUE , 1, FALSE, {CPN_RGBA_A} },
+
+ { N_("HSV"), "HSV", TRUE, 3, FALSE, {CPN_HSV_H, CPN_HSV_S, CPN_HSV_V} },
+ { N_("Hue"), "HSV", FALSE, 1, FALSE, {CPN_HSV_H} },
+ { N_("Saturation"), "HSV", FALSE, 1, FALSE, {CPN_HSV_S} },
+ { N_("Value"), "HSV", FALSE, 1, FALSE, {CPN_HSV_V} },
+
+ { N_("HSL"), "HSL", TRUE, 3, FALSE, {CPN_HSL_H, CPN_HSL_S, CPN_HSL_L} },
+ { N_("Hue (HSL)"), "HSL", FALSE, 1, FALSE, {CPN_HSL_H} },
+ { N_("Saturation (HSL)"), "HSL", FALSE, 1, FALSE, {CPN_HSL_S} },
+ { N_("Lightness"), "HSL", FALSE, 1, FALSE, {CPN_HSL_L} },
+
+ { N_("CMY"), "CMY", TRUE, 3, FALSE, {CPN_CMY_C, CPN_CMY_M, CPN_CMY_Y} },
+ { N_("Cyan"), "CMY", FALSE, 1, FALSE, {CPN_CMY_C} },
+ { N_("Magenta"), "CMY", FALSE, 1, FALSE, {CPN_CMY_M} },
+ { N_("Yeallow"), "CMY", FALSE, 1, FALSE, {CPN_CMY_Y} },
+
+ { N_("CMYK"), "CMYK", TRUE, 4, FALSE, {CPN_CMYK_C, CPN_CMYK_M, CPN_CMYK_Y, CPN_CMYK_K} },
+ { N_("Cyan_K"), "CMYK", FALSE, 1, FALSE, {CPN_CMYK_C} },
+ { N_("Magenta_K"), "CMYK", FALSE, 1, FALSE, {CPN_CMYK_M} },
+ { N_("Yellow_K"), "CMYK", FALSE, 1, FALSE, {CPN_CMYK_Y} },
+
+ { N_("LAB"), "CIE Lab", TRUE, 3, FALSE, {CPN_LAB_L, CPN_LAB_A, CPN_LAB_B} },
+
+ { N_("YCbCr_ITU_R470"), "Y'CbCr", TRUE, 3, FALSE, { CPN_YCBCR_Y, CPN_YCBCR_CB, CPN_YCBCR_CR} },
+ { N_("YCbCr ITU R470 256"), "Y'CbCr", TRUE, 3, TRUE, { CPN_YCBCR_Y, CPN_YCBCR_CB, CPN_YCBCR_CR} },
+
+ { N_("YCbCr_ITU_R709"), "Y'CbCr709", TRUE, 3, FALSE, { CPN_YCBCR709_Y, CPN_YCBCR709_CB,
CPN_YCBCR709_CR} },
+ { N_("YCbCr ITU R709 256"), "Y'CbCr709", TRUE, 3, TRUE, { CPN_YCBCR709_Y, CPN_YCBCR709_CB,
CPN_YCBCR709_CR} }
};
-typedef struct
-{
- gchar extract_type[32];
- gboolean as_layers;
- gboolean use_registration;
-} DecoVals;
-
const GimpPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
@@ -408,10 +469,11 @@ decompose (gint32 image_ID,
src_buffer = gimp_drawable_get_buffer (drawable_ID);
precision = gimp_image_get_precision (image_ID);
- for(j = 0; j < num_layers; j++)
+ for (j = 0; j < num_layers; j++)
{
- decomp_has_alpha |= !g_strcmp0 ("alpha", extract[extract_idx].component[j]);
- decomp_has_alpha |= !g_strcmp0 ("A", extract[extract_idx].component[j]);
+ /* FIXME: Not 100% reliable */
+ decomp_has_alpha |= !g_strcmp0 ("alpha", extract[extract_idx].component[j].babl_name);
+ decomp_has_alpha |= !g_strcmp0 ("A", extract[extract_idx].component[j].babl_name);
}
requirments |= (gimp_drawable_is_rgb (drawable_ID));
@@ -441,7 +503,7 @@ decompose (gint32 image_ID,
if (decovals.as_layers)
{
- layername = gettext (extract[extract_idx].channel_name[j]);
+ layername = gettext (extract[extract_idx].component[j].channel_name);
if (j == 0)
image_ID_dst[j] = create_new_image (filename, layername,
@@ -466,9 +528,7 @@ decompose (gint32 image_ID,
}
copy_n_components (src_buffer, dst_buffer,
- extract[extract_idx].model,
- extract[extract_idx].num_images,
- extract[extract_idx].component);
+ extract[extract_idx]);
if (decovals.use_registration)
transfer_registration_color (src_buffer, dst_buffer, num_layers);
@@ -610,26 +670,55 @@ transfer_registration_color (GeglBuffer *src,
}
static void
-copy_n_components (GeglBuffer *src,
- GeglBuffer **dst,
- const gchar *model,
- guint n,
- const gchar **components)
+cpn_affine_transform_clamp (GeglBuffer *buffer,
+ gdouble min,
+ gdouble max)
+{
+ GeglBufferIterator *gi;
+
+ gdouble scale = 1.0 / (max - min);
+ gdouble offset = - min;
+
+ /* We want to scale values linearly, regardless of the format of the buffer */
+ gegl_buffer_set_format (buffer, babl_format ("Y double"));
+
+ gi = gegl_buffer_iterator_new (buffer, NULL, 0, NULL,
+ GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (gi))
+ {
+ guint k;
+ double *data;
+
+ data = (double*) gi->data[0];
+
+ for (k = 0; k < gi->length; k++)
+ {
+ data[k] = CLAMP ((data[k] + offset) * scale, 0.0, 1.0);
+ }
+ }
+}
+
+static void
+copy_n_components (GeglBuffer *src,
+ GeglBuffer **dst,
+ EXTRACT ext)
{
gint i;
- for (i = 0; i < n; i++)
+ for (i = 0; i < ext.num_images; i++)
{
- gimp_progress_update ((gdouble) i / (gdouble) n);
- copy_one_component (src, dst[i], model, components[i]);
+ gimp_progress_update ((gdouble) i / (gdouble) ext.num_images);
+ copy_one_component (src, dst[i], ext.model, ext.component[i], ext.clamp);
}
}
static void
-copy_one_component (GeglBuffer *src,
- GeglBuffer *dst,
- const gchar *model,
- const gchar *component)
+copy_one_component (GeglBuffer *src,
+ GeglBuffer *dst,
+ const gchar *model,
+ const COMPONENT component,
+ gboolean clamp)
{
const Babl *component_format, *dst_format;
GeglBuffer *temp;
@@ -638,15 +727,15 @@ copy_one_component (GeglBuffer *src,
/* We are working in linear double precison*/
component_format = babl_format_new (babl_model (model),
babl_type ("double"),
- babl_component (component),
+ babl_component (component.babl_name),
NULL);
- /* Alpha case, we need to enforce linearity here
+ /* We need to enforce linearity here
* If the output is "Y'", the ouput of temp is already ok
- * If the output is "Y" , it will enforce gamma-decoding...
- * A bit tricky...
+ * If the output is "Y" , it will enforce gamma-decoding.
+ * A bit tricky and suboptimal...
*/
- if (!g_strcmp0 (component , "A"))
+ if (component.perceptual_channel)
dst_format = babl_format ("Y' double");
else
dst_format = babl_format ("Y double");
@@ -654,11 +743,14 @@ copy_one_component (GeglBuffer *src,
extent = gegl_buffer_get_extent (src);
temp = gegl_buffer_new (extent, dst_format);
- /* we want to copy the componnent as is */
+ /* we want to copy the component as is */
gegl_buffer_set_format (temp, component_format);
gegl_buffer_copy (src, NULL, temp, NULL);
- /* This is our new "Y(') double" componnent buffer */
+ if (component.range_min != 0.0 || component.range_max != 1.0 || clamp)
+ cpn_affine_transform_clamp (temp, component.range_min, component.range_max);
+
+ /* This is our new "Y(') double" component buffer */
gegl_buffer_set_format (temp, NULL);
/* Now we let babl convert it back to the format that dst needs */
@@ -833,7 +925,7 @@ generate_filename (guint32 image_ID, guint colorspace, guint channel)
extension);
else
filename = g_strdup_printf ("%s-%s.%s", fname,
- gettext (extract[colorspace].channel_name[channel]),
+ gettext (extract[colorspace].component[channel].channel_name),
extension);
}
else
@@ -843,12 +935,12 @@ generate_filename (guint32 image_ID, guint colorspace, guint channel)
gettext (extract[colorspace].type));
else
filename = g_strdup_printf ("%s-%s", fname,
- gettext (extract[colorspace].channel_name[channel]));
+ gettext (extract[colorspace].component[channel].channel_name));
}
}
else
{
- filename = g_strdup (gettext (extract[colorspace].channel_name[channel]));
+ filename = g_strdup (gettext (extract[colorspace].component[channel].channel_name));
}
g_free (fname);
return filename;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]