gnome-scan r725 - in trunk: . modules/gsane



Author: bersace
Date: Sun Dec 21 13:20:07 2008
New Revision: 725
URL: http://svn.gnome.org/viewvc/gnome-scan?rev=725&view=rev

Log:
Added support for 1bit and nbit depth.

Modified:
   trunk/ChangeLog
   trunk/modules/gsane/gsane-processor.c

Modified: trunk/modules/gsane/gsane-processor.c
==============================================================================
--- trunk/modules/gsane/gsane-processor.c	(original)
+++ trunk/modules/gsane/gsane-processor.c	Sun Dec 21 13:20:07 2008
@@ -21,15 +21,12 @@
 
 #include "gsane-processor.h"
 #include <string.h>
+#include <math.h>
 
 typedef void (*GSaneProcessorFunc) (GSaneProcessor *self, guchar *buf, guint buf_len);
 
 struct _GSaneProcessorPrivate {
 	const SANE_Parameters *params;
-	/* bytes per pixel in one frame (not final pixel stride). It
-	   is a sample stride for one sample frame. May be < 1 for
-	   depth < 8bit */
-	gdouble bytes_per_pixel;
 	/* output format of processor */
 	Babl* format;
 	/* target buffer */
@@ -37,16 +34,80 @@
 	/* rect representing the current buffer being processed. Might
 	   make sense to add a param instead ? */
 	volatile GeglRectangle rect;
+	/* The amount of pixel represented in the current buffer
+	   returned by SANE */
+	volatile guint pixels_in_buf;
 	/* total bytes read*/
 	volatile guint bytes_processed;
 	/* total number of frame to acquire to get the entire image */
 	guint frame_count;
+	guint sample_count;
 	/* offset of a sample in bytes for three-pass acquisition */
 	guint sample_offset;
+	/* maximum value for a sample, needed for non regular depth */
+	guint32 max_sample_value;
+	/* maximum value for a sample for Babl */
+	guint32 max_target_sample_value;
+	/* exact portion of bytes used to reprÃsent one pixel in the frame */
+	gdouble bytes_per_pixel;
+	/* minimal amount of bytes needed to contain one pixel */
+	guint pixel_stride;
+	/* minimal amount of bytes needed to contain one sample in the frame */
+	guint sample_stride;
+	/* number of bits needed for a pixel, useful for arbitrary depth */
+	guint bits_per_pixel;
+	/* pattern to match one pixel value in word */
+	guint32 pixel_pattern;
+	/* pattern to match on sample in a word */
+	guint32 sample_pattern;
 	/* pointer to the processor function */
 	GSaneProcessorFunc process;
 };
 
+static gchar*
+gsane_debug_byte(guchar val)
+{
+	guint i;
+	gchar* str = g_new0(gchar,1), *oldstr;
+	for(i = 0; i < 8; i++) {
+		oldstr = str;
+		str = g_strdup_printf("%d%s", val & (1<<i) ? 1 : 0, str);
+		g_free(oldstr);
+	}
+	return str;
+}
+
+static gchar*
+gsane_debug_byte_array(guchar*buf, guint buf_len)
+{
+	guint i;
+	gchar *str = g_new0(gchar,1), *oldstr;
+	for (i = 0; i < buf_len; i++) {
+		oldstr = str;
+		str = g_strdup_printf("%s%s", str, gsane_debug_byte(buf[i]));
+		if (oldstr)
+			g_free(oldstr);
+	}
+	return str;
+}
+
+static gchar*
+gsane_debug_int32(guint32 val)
+{
+	guint i;
+	gchar* str = g_new0(gchar,1), *oldstr;
+	for(i = 0; i < sizeof(val); i++) {
+		oldstr = str;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+		str = g_strdup_printf("%s%s", str, gsane_debug_byte(((guchar*)(&val))[i]));
+#else
+		str = g_strdup_printf("%s%s", gsane_debug_byte(((guchar*)(&val))[i]), str);
+#endif
+		g_free(oldstr);
+	}
+	return str;
+}
+
 void
 gsane_processor_init(GSaneProcessor *self)
 {
@@ -60,6 +121,19 @@
 {
 }
 
+static void
+gsane_processor_process_1bit(GSaneProcessor *self, guchar *buf, guint buf_len)
+{
+	GeglRectangle roi = self->priv->rect;
+	guchar*buf8 = g_new0(guchar, buf_len*8);
+	guint i, j;
+	for (i = 0; i < buf_len; i++)
+		for (j = 0; j < 8; j++)
+			buf8[i * 8 + j] = (buf[i] & (1 << (7 - j))) ? 0xFF : 0x00;
+	gegl_buffer_set(self->priv->buffer, &roi, self->priv->format, buf8, GEGL_AUTO_ROWSTRIDE);
+	g_free(buf8);
+}
+
 /* process Y or RGB 8/16 bit into â 8/16 bit. */
 static void
 gsane_processor_process_8bit(GSaneProcessor *self, guchar *buf, guint buf_len)
@@ -69,23 +143,63 @@
 }
 
 static void
+gsane_processor_process_nbit(GSaneProcessor *self, guchar *buf, guint buf_len)
+{
+	GeglRectangle roi = self->priv->rect;
+	guint i;
+	guint32 value = 0;	/* support up to 32 bit sample, we
+				   don't use an array due to bit
+				   operation */
+	guint src_pos;
+	guint offset;
+	guchar *src, *dest, *buf8 = g_new0(guchar, self->priv->pixels_in_buf * self->priv->format->format.bytes_per_pixel);
+	guint samples_in_buf = self->priv->pixels_in_buf * self->priv->sample_count;
+	for (i = 0 ; i < samples_in_buf ; i++) {
+		/* compute the address of the first byte container sample value */
+		src_pos = i * self->priv->bytes_per_pixel / self->priv->sample_count;
+		/* retrieve bytes containing sample value */
+		memcpy(&value, buf+src_pos, self->priv->sample_stride);
+		/* compute the offset of the samples bits inside the sample stride */
+		offset = (8 * self->priv->sample_stride) - ((i * self->priv->params->depth) - (src_pos * 8)) - 1;
+		/* align sample bits to the right */
+		value = value >> offset;
+		/* apply sample patter to get sample value */
+		value = value & self->priv->sample_pattern;
+		/* compute target value */
+		value = self->priv->max_target_sample_value * (value / self->priv->max_sample_value);
+		/* get the address of the first byte set. */
+		src = (guchar*)(&value);
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+		src = src + (sizeof(value) - self->priv->sample_stride);
+#endif
+		/* compute the first byte target address */
+		dest = buf8 + i * self->priv->sample_stride;
+		/* save */
+		memcpy(dest, src, self->priv->sample_stride);
+	}
+	/* send */
+	gegl_buffer_set(self->priv->buffer, &roi, self->priv->format, buf8, GEGL_AUTO_ROWSTRIDE);
+	g_free(buf8);
+}
+
+static void
 gsane_processor_process_three_pass_8bit(GSaneProcessor *self, guchar *buf, guint buf_len)
 {
 	GeglRectangle roi = self->priv->rect;
 	guchar *buf3 = g_new0(guchar, self->priv->frame_count*buf_len);
-	guint i, pix_count;
+	guint i;
 	guint src_pos, dest_pos;
 	gegl_buffer_get(self->priv->buffer, 1.0, &roi, self->priv->format, buf3, GEGL_AUTO_ROWSTRIDE);
-	/* number of pixels in buf */
-	pix_count = buf_len / self->priv->bytes_per_pixel;
 	/* copy pixel per pixel from buf to buf3 */
-	for (i = 0; i < pix_count; i++) {
+	for (i = 0; i < self->priv->pixels_in_buf; i++) {
 		/* pos of pixel i in buf */
 		src_pos = i * self->priv->bytes_per_pixel;
 		/* pos of pixel i in buf3 */
 		dest_pos = i * self->priv->format->format.bytes_per_pixel + self->priv->sample_offset;
+		/* save */
 		memcpy(buf3+dest_pos, buf+src_pos, self->priv->bytes_per_pixel);
 	}
+	/* send */
 	gegl_buffer_set(self->priv->buffer, &roi, self->priv->format, buf3, GEGL_AUTO_ROWSTRIDE);
 	g_free(buf3);
 }
@@ -97,10 +211,12 @@
 	switch(self->priv->params->format) {
 	case SANE_FRAME_RGB:
 	case SANE_FRAME_GRAY:
-		if (self->priv->params->depth%8 == 0)
+		if (self->priv->params->depth % 8 == 0)
 			func = gsane_processor_process_8bit;
+		else if (self->priv->params->depth == 1)
+			func = gsane_processor_process_1bit;
 		else
-			g_warning("Unsupported %dbit frame format.", self->priv->params->depth);
+			func = gsane_processor_process_nbit;
 		break;
 	case SANE_FRAME_RED:
 	case SANE_FRAME_GREEN:
@@ -192,8 +308,14 @@
 	};
 
 	self->priv->params = params;
-	self->priv->frame_count = frame_count;
-	self->priv->bytes_per_pixel = (gdouble)params->bytes_per_line / (gdouble)params->pixels_per_line;
+	self->priv->frame_count		= frame_count;
+	self->priv->bytes_per_pixel	= (gdouble)params->bytes_per_line / (gdouble)params->pixels_per_line;
+	self->priv->pixel_stride	= floor(self->priv->bytes_per_pixel) + (self->priv->bytes_per_pixel > (gdouble)((guint) self->priv->bytes_per_pixel) ? 1 : 0);
+	self->priv->bits_per_pixel	= 8 * self->priv->bytes_per_pixel;
+	self->priv->sample_count	= self->priv->bits_per_pixel / self->priv->params->depth;
+	self->priv->max_sample_value	= (0xFFFFFFFF) >> (32 - self->priv->params->depth);
+	self->priv->pixel_pattern	= (0xFFFFFFFF) >> (32 - self->priv->bits_per_pixel);
+	self->priv->sample_pattern	= (0xFFFFFFFF) >> (32 - self->priv->params->depth);
 
 	self->priv->process = gsane_processor_get_func(self);
 	g_return_val_if_fail(self->priv->process, NULL);
@@ -201,6 +323,9 @@
 	self->priv->format = gsane_processor_get_babl_format(self);
 	g_return_val_if_fail(self->priv->format, NULL);
 
+	self->priv->sample_stride	= self->priv->format->format.bytes_per_pixel / self->priv->sample_count;
+	self->priv->max_target_sample_value= (0xFFFFFFFF) >> (32 - self->priv->format->format.bytes_per_pixel / self->priv->sample_count * 8);
+
 	self->priv->buffer = gegl_buffer_new(&extent, self->priv->format);
 	return self->priv->buffer;
 }
@@ -225,15 +350,15 @@
 	self->priv->rect.y = self->priv->bytes_processed / self->priv->params->bytes_per_line;
 	self->priv->rect.x = self->priv->bytes_processed % self->priv->params->bytes_per_line;
 	guint pixel_to_end_of_line = self->priv->params->pixels_per_line - self->priv->rect.x;
-	guint pixels_in_buf = (gdouble)buf_len / self->priv->bytes_per_pixel;
-	self->priv->rect.width = MIN (pixels_in_buf - self->priv->rect.x, pixel_to_end_of_line);
+	self->priv->pixels_in_buf = (gdouble)buf_len / self->priv->bytes_per_pixel;
+	self->priv->rect.width = MIN (self->priv->pixels_in_buf - self->priv->rect.x, pixel_to_end_of_line);
 
 	/* compute the height of the rect and determine whether buf is
 	   in several rect */
 	if (self->priv->rect.x > 0) {
 		/* first rect is one line */
 		self->priv->rect.height = 1;
-		if (pixels_in_buf > self->priv->rect.width) {
+		if (self->priv->pixels_in_buf > self->priv->rect.width) {
 			/* recursion for the rest (will start at x=0) */
 			bytes_processed = self->priv->rect.width * self->priv->bytes_per_pixel;
 			next_buf_len = buf_len - bytes_processed;
@@ -242,8 +367,8 @@
 	}
 	else {
 		/* multiline */
-		self->priv->rect.height = pixels_in_buf / self->priv->rect.width;
-		guint last_line_length = pixels_in_buf % self->priv->rect.width;
+		self->priv->rect.height = self->priv->pixels_in_buf / self->priv->rect.width;
+		guint last_line_length = self->priv->pixels_in_buf % self->priv->rect.width;
 		if (last_line_length > 0) {
 			/* the last line needs recursion */
 			next_buf_len = last_line_length * self->priv->bytes_per_pixel;
@@ -253,6 +378,7 @@
 	}
 
 	/* process */
+	/* g_debug("Processing %dx%d+%d+%d", self->priv->rect.width, self->priv->rect.height, self->priv->rect.x, self->priv->rect.y); */
 	self->priv->process(self, buf, buf_len);
 	self->priv->bytes_processed+= bytes_processed;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]