[Rawstudio-commit] r2194 - in trunk: . plugins plugins/resample

Anders Brander anders at brander.dk
Sun Feb 1 04:50:50 CET 2009


Author: abrander
Date: 2009-02-01 04:50:50 +0100 (Sun, 01 Feb 2009)
New Revision: 2194

Added:
   trunk/plugins/resample/
   trunk/plugins/resample/Makefile.am
   trunk/plugins/resample/resample.c
Modified:
   trunk/configure.in
   trunk/plugins/Makefile.am
Log:
Added RSResample-filter (Patch by Klaus Post).

Modified: trunk/configure.in
===================================================================
--- trunk/configure.in	2009-02-01 00:40:29 UTC (rev 2193)
+++ trunk/configure.in	2009-02-01 03:50:50 UTC (rev 2194)
@@ -89,6 +89,7 @@
 plugins/meta-raf/Makefile
 plugins/meta-tiff/Makefile
 plugins/meta-x3f/Makefile
+plugins/resample/Makefile
 plugins/rotate/Makefile
 plugins/sharpen/Makefile
 plugins/transform/Makefile

Modified: trunk/plugins/Makefile.am
===================================================================
--- trunk/plugins/Makefile.am	2009-02-01 00:40:29 UTC (rev 2193)
+++ trunk/plugins/Makefile.am	2009-02-01 03:50:50 UTC (rev 2194)
@@ -13,6 +13,7 @@
 	meta-raf \
 	meta-tiff \
 	meta-x3f \
+	resample \
 	rotate \
 	sharpen \
 	transform

Added: trunk/plugins/resample/Makefile.am
===================================================================
--- trunk/plugins/resample/Makefile.am	                        (rev 0)
+++ trunk/plugins/resample/Makefile.am	2009-02-01 03:50:50 UTC (rev 2194)
@@ -0,0 +1,21 @@
+plugindir = $(libdir)/rawstudio/plugins
+
+AM_CFLAGS =\
+	-Wall\
+	-O4
+
+AM_CXXFLAGS = $(AM_CFLAGS)
+
+INCLUDES = \
+	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+	@PACKAGE_CFLAGS@ \
+	-I../../librawstudio/
+
+lib_LTLIBRARIES = resample.la
+
+libdir = $(datadir)/rawstudio/plugins/
+
+resample_la_LIBADD = @PACKAGE_LIBS@
+resample_la_LDFLAGS = -module -avoid-version
+resample_la_SOURCES = resample.c

Added: trunk/plugins/resample/resample.c
===================================================================
--- trunk/plugins/resample/resample.c	                        (rev 0)
+++ trunk/plugins/resample/resample.c	2009-02-01 03:50:50 UTC (rev 2194)
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2006-2008 Anders Brander <anders at brander.dk> and 
+ * Anders Kvist <akv at lnxbx.dk>
+ *
+ * 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 4 */
+
+#include <rawstudio.h>
+#include <math.h>
+
+#define RS_TYPE_RESAMPLE (rs_resample_type)
+#define RS_RESAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RS_TYPE_RESAMPLE, RSResample))
+#define RS_RESAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), RS_TYPE_RESAMPLE, RSResampleClass))
+#define RS_IS_RESAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RS_TYPE_RESAMPLE))
+
+typedef struct _RSResample RSResample;
+typedef struct _RSResampleClass RSResampleClass;
+
+struct _RSResample {
+	RSFilter parent;
+
+	gint new_width;
+	gint new_height;
+};
+
+struct _RSResampleClass {
+	RSFilterClass parent_class;
+};
+
+RS_DEFINE_FILTER(rs_resample, RSResample)
+
+enum {
+	PROP_0,
+	PROP_WIDTH,
+	PROP_HEIGHT
+};
+
+static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static RS_IMAGE16 *get_image(RSFilter *filter);
+static gint get_width(RSFilter *filter);
+static gint get_height(RSFilter *filter);
+static RS_IMAGE16 *ResizeH(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y);
+static RS_IMAGE16 *ResizeV(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x);
+
+static RSFilterClass *rs_resample_parent_class = NULL;
+
+G_MODULE_EXPORT void
+rs_plugin_load(RSPlugin *plugin)
+{
+	rs_resample_get_type(G_TYPE_MODULE(plugin));
+}
+
+static void
+rs_resample_class_init(RSResampleClass *klass)
+{
+	RSFilterClass *filter_class = RS_FILTER_CLASS (klass);
+	GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+	rs_resample_parent_class = g_type_class_peek_parent (klass);
+
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	g_object_class_install_property(object_class,
+		PROP_WIDTH, g_param_spec_int(
+			"width", "width", "The width of the scaled image",
+			6, 65535, 100, G_PARAM_READWRITE)
+	);
+	g_object_class_install_property(object_class,
+		PROP_HEIGHT, g_param_spec_int(
+			"height", "height", "The height of the scaled image",
+			6, 65535, 100, G_PARAM_READWRITE)
+	);
+
+	filter_class->name = "Resample filter";
+	filter_class->get_image = get_image;
+	filter_class->get_width = get_width;
+	filter_class->get_height = get_height;
+}
+
+static void
+rs_resample_init(RSResample *resample)
+{
+	resample->new_width = 400;
+	resample->new_height = 400;
+}
+
+static void
+get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	RSResample *resample = RS_RESAMPLE(object);
+
+	switch (property_id)
+	{
+		case PROP_WIDTH:
+			g_value_set_int(value, resample->new_width);
+			break;
+		case PROP_HEIGHT:
+			g_value_set_int(value, resample->new_height);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	RSResample *resample = RS_RESAMPLE(object);
+
+	switch (property_id)
+	{
+		case PROP_WIDTH:
+			resample->new_width = g_value_get_int(value);
+			rs_filter_changed(RS_FILTER(object));
+			break;
+		case PROP_HEIGHT:
+			resample->new_height = g_value_get_int(value);
+			rs_filter_changed(RS_FILTER(object));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static RS_IMAGE16 *
+get_image(RSFilter *filter)
+{
+	RSResample *resample = RS_RESAMPLE(filter);
+	RS_IMAGE16 *temp;
+	RS_IMAGE16 *input;
+	RS_IMAGE16 *output = NULL;
+	gint input_width = rs_filter_get_width(filter->previous);
+	gint input_height = rs_filter_get_height(filter->previous);
+
+	input = rs_filter_get_image(filter->previous);
+
+	/* Simply return the input, if we don't scale */
+	if ((input_width == resample->new_width) && (input_height == resample->new_height))
+		return input;
+
+	temp = ResizeH(input, input_width, resample->new_width, input_height);
+	output = ResizeV(temp, input_height, resample->new_height, temp->w);
+	g_object_unref(temp);
+
+	g_object_unref(input);
+	return output;
+}
+
+static gint
+get_width(RSFilter *filter)
+{
+	RSResample *resample = RS_RESAMPLE(filter);
+
+	return resample->new_width;
+}
+
+static gint
+get_height(RSFilter *filter)
+{
+	RSResample *resample = RS_RESAMPLE(filter);
+
+	return resample->new_height;
+}
+
+static guint
+lanczos_taps()
+{
+	return 3;
+}
+
+static gdouble
+lanczos_sinc(gdouble value)
+{
+	if (value != 0.0)
+	{
+		value *= M_PI;
+		return sin(value) / value;
+	}
+	else
+		return 1.0;
+}
+
+static gdouble
+sinc(gdouble value)
+{
+	if (value != 0.0)
+	{
+		value *= M_PI;
+		return sin(value) / value;
+	}
+	else
+		return 1.0;
+}
+
+static gdouble
+lanczos_weight(gdouble value)
+{
+	value = fabs(value);
+	if (value < lanczos_taps())
+	{
+		return (sinc(value) * sinc(value / lanczos_taps()));
+	}
+	else
+		return 0.0;
+}
+
+const static gint FPScale = 16384; /* fixed point scaler */
+const static gint FPScaleShift = 14; /* fixed point scaler */
+
+static RS_IMAGE16 *
+ResizeH(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y)
+{
+	gdouble pos_step = ((gdouble) old_size) / ((gdouble)new_size);
+	gdouble filter_step = MIN(pos_step, 1.0);
+	gdouble filter_support = (gdouble) lanczos_taps() / filter_step;
+	gint fir_filter_size = (gint) (ceil(filter_support*2));
+	gint *weights = g_new(gint, new_size * fir_filter_size);
+	gint *offsets = g_new(gint, new_size);
+
+	RS_IMAGE16 *output = rs_image16_new(new_size, insize_y, 3, 4);
+
+	g_assert(new_size > fir_filter_size);
+
+	gdouble pos = 0.0;
+	gint i,j,k;
+
+	for (i=0; i<new_size; ++i)
+	{
+		gint end_pos = (gint) (pos + filter_support);
+
+		if (end_pos > old_size-1)
+			end_pos = old_size-1;
+
+		gint start_pos = end_pos - fir_filter_size + 1;
+
+		if (start_pos < 0)
+			start_pos = 0;
+
+		offsets[i] = start_pos * 4;
+
+		/* the following code ensures that the coefficients add to exactly FPScale */
+		gdouble total = 0.0;
+
+		/* Ensure that we have a valid position */
+		gdouble ok_pos = MAX(0.0,MIN(old_size-1,pos));
+
+		for (j=0; j<fir_filter_size; ++j)
+		{
+			/* Accumulate all coefficients */
+			total += lanczos_weight((start_pos+j - ok_pos) * filter_step);
+		}
+
+		g_assert(total > 0.0f);
+
+		gdouble total2 = 0.0;
+
+		for (k=0; k<fir_filter_size; ++k)
+		{
+			gdouble total3 = total2 + lanczos_weight((start_pos+k - ok_pos) * filter_step) / total;
+			weights[i*fir_filter_size+k] = (gint) (total3*FPScale+0.5) - (gint) (total2*FPScale+0.5);
+			total2 = total3;
+		}
+		pos += pos_step;
+	}
+
+	g_assert(input->pixelsize == 4);
+	g_assert(input->channels == 3);
+
+	guint y,x;
+	for (y = 0; y < insize_y ; y++)
+	{
+		gushort *in_line = GET_PIXEL(input, 0, y);
+		gushort *out = GET_PIXEL(output, 0, y);
+		gint *wg = weights;
+
+		for (x = 0; x < new_size; x++)
+		{
+			guint i;
+			gushort *in = &in_line[offsets[x]];
+			gint acc1 = 0;
+			gint acc2 = 0;
+			gint acc3 = 0;
+
+			for (i = 0; i <fir_filter_size; i++)
+			{
+				gint w = *wg++;
+				acc1 += in[i*4]*w;
+				acc2 += in[i*4+1]*w;
+				acc3 += in[i*4+2]*w;
+			}
+			out[x*4] = CLAMP((acc1 + (FPScale/2))>>FPScaleShift, 0, 65535);
+			out[x*4+1] = CLAMP((acc2 + (FPScale/2))>>FPScaleShift, 0, 65535);
+			out[x*4+2] = CLAMP((acc3 + (FPScale/2))>>FPScaleShift, 0, 65535);
+		}
+	}
+
+	g_free(weights);
+	g_free(offsets);
+
+	return output;
+}
+
+static RS_IMAGE16 *
+ResizeV(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x)
+{
+	gdouble pos_step = ((gdouble) old_size) / ((gdouble)new_size);
+	gdouble filter_step = MIN(pos_step, 1.0);
+	gdouble filter_support = (gdouble) lanczos_taps() / filter_step;
+	gint fir_filter_size = (gint) (ceil(filter_support*2));
+	gint *weights = g_new(gint, new_size * fir_filter_size);
+	gint *offsets = g_new(gint, new_size);
+
+	RS_IMAGE16 *output = rs_image16_new(insize_x, new_size, 3, 4);
+
+	g_assert(new_size > fir_filter_size);
+
+	gdouble pos = 0.0;
+
+	gint i,j,k;
+
+	for (i=0; i<new_size; ++i)
+	{
+		gint end_pos = (gint) (pos + filter_support);
+		if (end_pos > old_size-1)
+			end_pos = old_size-1;
+
+		gint start_pos = end_pos - fir_filter_size + 1;
+
+		if (start_pos < 0)
+			start_pos = 0;
+
+		offsets[i] = start_pos;
+
+		/* The following code ensures that the coefficients add to exactly FPScale */
+		gdouble total = 0.0;
+
+		/* Ensure that we have a valid position */
+		gdouble ok_pos = MAX(0.0,MIN(old_size-1,pos));
+
+		for (j=0; j<fir_filter_size; ++j)
+		{
+			/* Accumulate all coefficients */
+			total += lanczos_weight((start_pos+j - ok_pos) * filter_step);
+		}
+
+		g_assert(total > 0.0f);
+
+		gdouble total2 = 0.0;
+
+		for (k=0; k<fir_filter_size; ++k)
+		{
+			gdouble total3 = total2 + lanczos_weight((start_pos+k - ok_pos) * filter_step) / total;
+			weights[i*fir_filter_size+k] = (gint) (total3*FPScale+0.5) - (gint) (total2*FPScale+0.5);
+			total2 = total3;
+		}
+		pos += pos_step;
+	}
+
+	g_assert(input->pixelsize == 4);
+	g_assert(input->channels == 3);
+
+	guint y,x;
+    gint *wg = weights;
+	
+	for (y = 0; y < new_size ; y++)
+	{
+		gushort *in = GET_PIXEL(input, 0, offsets[y]);
+		gushort *out = GET_PIXEL(output, 0, y);
+		for (x = 0; x < insize_x; x++)
+		{
+			gint acc1 = 0;
+			gint acc2 = 0;
+			gint acc3 = 0;
+			for (i = 0; i < fir_filter_size; i++)
+			{
+				acc1 += in[i*input->rowstride]* wg[i];
+				acc2 += in[i*input->rowstride+1] * wg[i];
+				acc3 += in[i*input->rowstride+2] * wg[i];
+			}
+			out[x*4] = CLAMP((acc1 + (FPScale/2))>>FPScaleShift, 0, 65535);
+			out[x*4+1] = CLAMP((acc2 + (FPScale/2))>>FPScaleShift, 0, 65535);
+			out[x*4+2] = CLAMP((acc3 + (FPScale/2))>>FPScaleShift, 0, 65535);
+			in+=4;
+		}
+		wg+=fir_filter_size;
+	}
+
+	g_free(weights);
+	g_free(offsets);
+
+	return output;
+}




More information about the Rawstudio-commit mailing list