Author: abrander
Date: 2009-12-01 01:21:41 +0100 (Tue, 01 Dec 2009)
New Revision: 2775
Added:
trunk/plugins/colorspace-transform/
trunk/plugins/colorspace-transform/Makefile.am
trunk/plugins/colorspace-transform/colorspace_transform.c
Modified:
trunk/configure.in
trunk/plugins/Makefile.am
Log:
Added RSColorspaceTransform to convert between well defined color spaces.
Modified: trunk/configure.in
===================================================================
--- trunk/configure.in 2009-12-01 00:12:13 UTC (rev 2774)
+++ trunk/configure.in 2009-12-01 00:21:41 UTC (rev 2775)
@@ -79,6 +79,7 @@
plugins/cache/Makefile
plugins/colorspace-prophoto/Makefile
plugins/colorspace-srgb/Makefile
+plugins/colorspace-transform/Makefile
plugins/crop/Makefile
plugins/dcp/Makefile
plugins/demosaic/Makefile
Modified: trunk/plugins/Makefile.am
===================================================================
--- trunk/plugins/Makefile.am 2009-12-01 00:12:13 UTC (rev 2774)
+++ trunk/plugins/Makefile.am 2009-12-01 00:21:41 UTC (rev 2775)
@@ -3,6 +3,7 @@
cache \
colorspace-prophoto \
colorspace-srgb \
+ colorspace-transform \
crop \
dcp \
demosaic \
Added: trunk/plugins/colorspace-transform/Makefile.am
===================================================================
--- trunk/plugins/colorspace-transform/Makefile.am
(rev 0)
+++ trunk/plugins/colorspace-transform/Makefile.am 2009-12-01 00:21:41 UTC
(rev 2775)
@@ -0,0 +1,21 @@
+plugindir = $(libdir)/rawstudio/plugins
+
+AM_CFLAGS =\
+ -Wall\
+ -g3
+
+AM_CXXFLAGS = $(AM_CFLAGS)
+
+INCLUDES = \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ @PACKAGE_CFLAGS@ \
+ -I../../librawstudio/
+
+lib_LTLIBRARIES = colorspace_transform.la
+
+libdir = $(datadir)/rawstudio/plugins/
+
+colorspace_transform_la_LIBADD = @PACKAGE_LIBS@
+colorspace_transform_la_LDFLAGS = -module -avoid-version
+colorspace_transform_la_SOURCES = colorspace_transform.c
Added: trunk/plugins/colorspace-transform/colorspace_transform.c
===================================================================
--- trunk/plugins/colorspace-transform/colorspace_transform.c
(rev 0)
+++ trunk/plugins/colorspace-transform/colorspace_transform.c 2009-12-01
00:21:41 UTC (rev 2775)
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2006-2009 Anders Brander <[email protected]> and
+ * Anders Kvist <[email protected]>
+ *
+ * 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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
+ */
+
+/* Plugin tmpl version 5 */
+
+#include <rawstudio.h>
+#include <lcms.h>
+
+#define RS_TYPE_COLORSPACE_TRANSFORM (rs_colorspace_transform_type)
+#define RS_COLORSPACE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
RS_TYPE_COLORSPACE_TRANSFORM, RSColorspaceTransform))
+#define RS_COLORSPACE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST
((klass), RS_TYPE_COLORSPACE_TRANSFORM, RSColorspaceTransformClass))
+#define RS_IS_COLORSPACE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
RS_TYPE_COLORSPACE_TRANSFORM))
+
+typedef struct _RSColorspaceTransform RSColorspaceTransform;
+typedef struct _RSColorspaceTransformClass RSColorspaceTransformClass;
+
+struct _RSColorspaceTransform {
+ RSFilter parent;
+
+};
+
+struct _RSColorspaceTransformClass {
+ RSFilterClass parent_class;
+};
+
+RS_DEFINE_FILTER(rs_colorspace_transform, RSColorspaceTransform)
+
+enum {
+ PROP_0,
+ PROP_CHANGEME
+};
+
+static RSFilterResponse *get_image(RSFilter *filter, const RSFilterRequest
*request);
+static RSFilterResponse *get_image8(RSFilter *filter, const RSFilterRequest
*request);
+static void convert_colorspace16(RSColorspaceTransform *colorspace_transform,
RS_IMAGE16 *input_image, RS_IMAGE16 *output_image, RSColorSpace *input_space,
RSColorSpace *output_space);
+static void convert_colorspace8(RSColorspaceTransform *colorspace_transform,
RS_IMAGE16 *input_image, GdkPixbuf *output_image, RSColorSpace *input_space,
RSColorSpace *output_space);
+
+static RSFilterClass *rs_colorspace_transform_parent_class = NULL;
+
+G_MODULE_EXPORT void
+rs_plugin_load(RSPlugin *plugin)
+{
+ rs_colorspace_transform_get_type(G_TYPE_MODULE(plugin));
+}
+
+static void
+rs_colorspace_transform_class_init(RSColorspaceTransformClass *klass)
+{
+ RSFilterClass *filter_class = RS_FILTER_CLASS (klass);
+
+ rs_colorspace_transform_parent_class = g_type_class_peek_parent (klass);
+
+ filter_class->name = "ColorspaceTransform filter";
+ filter_class->get_image = get_image;
+ filter_class->get_image8 = get_image8;
+}
+
+static void
+rs_colorspace_transform_init(RSColorspaceTransform *colorspace_transform)
+{
+}
+
+static RSFilterResponse *
+get_image(RSFilter *filter, const RSFilterRequest *request)
+{
+ RSColorspaceTransform *colorspace_transform =
RS_COLORSPACE_TRANSFORM(filter);
+ RSFilterResponse *previous_response;
+ RSFilterResponse *response;
+ RS_IMAGE16 *input;
+ RS_IMAGE16 *output = NULL;
+
+ previous_response = rs_filter_get_image(filter->previous, request);
+ input = rs_filter_response_get_image(previous_response);
+ if (!RS_IS_IMAGE16(input))
+ return previous_response;
+
+ RSColorSpace *input_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(previous_response),
"colorspace", RS_TYPE_COLOR_SPACE);
+ RSColorSpace *output_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(request), "colorspace",
RS_TYPE_COLOR_SPACE);
+
+ response = rs_filter_response_clone(previous_response);
+ g_object_unref(previous_response);
+ output = rs_image16_copy(input, FALSE);
+
+ convert_colorspace16(colorspace_transform, input, output, input_space,
output_space);
+
+ rs_filter_response_set_image(response, output);
+ g_object_unref(output);
+
+ /* Process output */
+
+ g_object_unref(input);
+ return response;
+}
+
+static RSFilterResponse *
+get_image8(RSFilter *filter, const RSFilterRequest *request)
+{
+ RSColorspaceTransform *colorspace_transform =
RS_COLORSPACE_TRANSFORM(filter);
+ RSFilterResponse *previous_response;
+ RSFilterResponse *response;
+ RS_IMAGE16 *input;
+ GdkPixbuf *output = NULL;
+
+ previous_response = rs_filter_get_image(filter->previous, request);
+ input = rs_filter_response_get_image(previous_response);
+ if (!RS_IS_IMAGE16(input))
+ return previous_response;
+
+ RSColorSpace *input_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(previous_response),
"colorspace", RS_TYPE_COLOR_SPACE);
+ RSColorSpace *output_space =
rs_filter_param_get_object_with_type(RS_FILTER_PARAM(request), "colorspace",
RS_TYPE_COLOR_SPACE);
+
+ response = rs_filter_response_clone(previous_response);
+ g_object_unref(previous_response);
+ output = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, input->w,
input->h);
+
+ convert_colorspace8(colorspace_transform, input, output, input_space,
output_space);
+
+ rs_filter_response_set_image8(response, output);
+ g_object_unref(output);
+
+ /* Process output */
+
+ g_object_unref(input);
+ return response;
+}
+
+//static cmsHTRANSFORM
+//get_lcms_transform16(RSColorspaceTransform *colorspace_transform,
RSIccProfile *input_profile, RSIccProfile *output_profile)
+//{
+//}
+
+static void
+transform8_c(RS_IMAGE16 *input, GdkPixbuf *output, RS_MATRIX3 *matrix, guchar
*table8)
+{
+ gint row;
+ gint r,g,b;
+ gint width;
+ RS_MATRIX3Int mati;
+
+ gint o_channels = gdk_pixbuf_get_n_channels(output);
+
+ matrix3_to_matrix3int(matrix, &mati);
+
+ for(row=0 ; row<input->h ; row++)
+ {
+ gushort *i = GET_PIXEL(input, 0, row);
+ guchar *o = GET_PIXBUF_PIXEL(output, 0, row);
+
+ width = input->w;
+
+ while(width--)
+ {
+ r =
+ ( i[R] * mati.coeff[0][0]
+ + i[G] * mati.coeff[0][1]
+ + i[B] * mati.coeff[0][2]
+ + 128 ) >> 8;
+ g =
+ ( i[R] * mati.coeff[1][0]
+ + i[G] * mati.coeff[1][1]
+ + i[B] * mati.coeff[1][2]
+ + 128 ) >> 8;
+ b =
+ ( i[R] * mati.coeff[2][0]
+ + i[G] * mati.coeff[2][1]
+ + i[B] * mati.coeff[2][2]
+ + 128 ) >> 8;
+
+ r = CLAMP(r, 0, 65535);
+ g = CLAMP(g, 0, 65535);
+ b = CLAMP(b, 0, 65535);
+
+ o[R] = table8[r];
+ o[G] = table8[g];
+ o[B] = table8[b];
+ i += input->pixelsize;
+ o += o_channels;
+ }
+ }
+}
+
+static void
+transform16_c(gushort *input, gushort *output, gint num_pixels, const gint
pixelsize, RS_MATRIX3 *matrix)
+{
+ gint r,g,b;
+ RS_MATRIX3Int mati;
+
+ matrix3_to_matrix3int(matrix, &mati);
+
+ while(num_pixels--)
+ {
+ r =
+ ( input[R] * mati.coeff[0][0]
+ + input[G] * mati.coeff[0][1]
+ + input[B] * mati.coeff[0][2]
+ + 128 ) >> 8;
+ g =
+ ( input[R] * mati.coeff[1][0]
+ + input[G] * mati.coeff[1][1]
+ + input[B] * mati.coeff[1][2]
+ + 128 ) >> 8;
+ b =
+ ( input[R] * mati.coeff[2][0]
+ + input[G] * mati.coeff[2][1]
+ + input[B] * mati.coeff[2][2]
+ + 128 ) >> 8;
+
+ r = CLAMP(r, 0, 65535);
+ g = CLAMP(g, 0, 65535);
+ b = CLAMP(b, 0, 65535);
+
+ output[R] = r;
+ output[G] = g;
+ output[B] = b;
+
+ input += pixelsize;
+ output += pixelsize;
+ }
+}
+
+static void
+convert_colorspace16(RSColorspaceTransform *colorspace_transform, RS_IMAGE16
*input_image, RS_IMAGE16 *output_image, RSColorSpace *input_space, RSColorSpace
*output_space)
+{
+ g_assert(RS_IS_IMAGE16(input_image));
+ g_assert(RS_IS_IMAGE16(output_image) || (output_image == NULL));
+ g_assert(RS_IS_COLOR_SPACE(input_space));
+ g_assert(RS_IS_COLOR_SPACE(output_space));
+
+ /* Do the transformation inplace if needed */
+ if (output_image == NULL)
+ output_image = input_image;
+
+ /* If both input/output images and colorspace are the same, return
immediately */
+ if ((input_image == output_image) && (input_space == output_space))
+ return;
+
+ /* A few sanity checks */
+ if (input_image->w != output_image->w)
+ return;
+ if (input_image->h != output_image->h)
+ return;
+
+ /* If input/output-image differ, but colorspace is the same, do a
simple copy */
+ else if (input_space == output_space)
+ {
+ /* FIXME: Do some sanity checking! */
+ memcpy(output_image->pixels, input_image->pixels,
input_image->rowstride*input_image->h*2);
+ }
+
+ /* If a CMS is needed, do the transformation using LCMS */
+ else if (RS_COLOR_SPACE_REQUIRES_CMS(input_space) ||
RS_COLOR_SPACE_REQUIRES_CMS(output_space))
+ {
+ g_warning("FIXME: (stub) LCMS support is not implemented yet");
+ memcpy(output_image->pixels, input_image->pixels,
input_image->rowstride*input_image->h*2);
+ }
+
+ /* If we get here, we can transform using simple vector math */
+ else
+ {
+ const RS_MATRIX3 a =
rs_color_space_get_matrix_from_pcs(input_space);
+ const RS_MATRIX3 b =
rs_color_space_get_matrix_to_pcs(output_space);
+ RS_MATRIX3 mat;
+ matrix3_multiply(&b, &a, &mat);
+
+ transform16_c(
+ GET_PIXEL(input_image, 0, 0),
+ GET_PIXEL(output_image, 0, 0),
+ input_image->h * input_image->pitch,
+ input_image->pixelsize,
+ &mat);
+ }
+}
+
+static void
+convert_colorspace8(RSColorspaceTransform *colorspace_transform, RS_IMAGE16
*input_image, GdkPixbuf *output_image, RSColorSpace *input_space, RSColorSpace
*output_space)
+{
+ g_assert(RS_IS_IMAGE16(input_image));
+ g_assert(GDK_IS_PIXBUF(output_image));
+ g_assert(RS_IS_COLOR_SPACE(input_space));
+ g_assert(RS_IS_COLOR_SPACE(output_space));
+
+ /* A few sanity checks */
+ if (input_image->w != gdk_pixbuf_get_width(output_image))
+ return;
+ if (input_image->h != gdk_pixbuf_get_height(output_image))
+ return;
+
+ /* If a CMS is needed, do the transformation using LCMS */
+ if (RS_COLOR_SPACE_REQUIRES_CMS(input_space) ||
RS_COLOR_SPACE_REQUIRES_CMS(output_space))
+ {
+ g_warning("FIXME: (stub) LCMS support is not implemented yet");
+ }
+
+ /* If we get here, we can transform using simple vector math and a
lookup table */
+// else
+ {
+ const RS_MATRIX3 a =
rs_color_space_get_matrix_from_pcs(input_space);
+ const RS_MATRIX3 b =
rs_color_space_get_matrix_to_pcs(output_space);
+ RS_MATRIX3 mat;
+ matrix3_multiply(&b, &a, &mat);
+
+ /* Calculate our gamma table */
+ /* FIXME: Move this to someplace where we can cache it! */
+ guchar table8[65536];
+ gint i;
+
+ const RS1dFunction *input_gamma =
rs_color_space_get_gamma_function(input_space);
+ const RS1dFunction *output_gamma =
rs_color_space_get_gamma_function(output_space);
+
+ for(i=0;i<65536;i++)
+ {
+ gdouble nd = ((gdouble) i) * (1.0/65535.0);
+
+ nd = rs_1d_function_evaluate_inverse(input_gamma, nd);
+ nd = rs_1d_function_evaluate(output_gamma, nd);
+
+ /* 8 bit output */
+ gint res = (gint) (nd*255.0);
+ _CLAMP255(res);
+ table8[i] = res;
+ }
+
+ transform8_c(
+ input_image,
+ output_image,
+ &mat,
+ table8);
+ }
+}
_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit