gnome-scan r725 - in trunk: . modules/gsane
- From: bersace svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-scan r725 - in trunk: . modules/gsane
- Date: Sun, 21 Dec 2008 13:20:07 +0000 (UTC)
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]