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



Author: bersace
Date: Sat Dec 20 19:02:43 2008
New Revision: 721
URL: http://svn.gnome.org/viewvc/gnome-scan?rev=721&view=rev

Log:
Support hand scanner.

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

Modified: trunk/modules/gsane/gsane-processor.c
==============================================================================
--- trunk/modules/gsane/gsane-processor.c	(original)
+++ trunk/modules/gsane/gsane-processor.c	Sat Dec 20 19:02:43 2008
@@ -165,14 +165,19 @@
 	GeglRectangle extent = {
 		.x = 0, .y = 0,
 		.width = params->pixels_per_line,
-		.height = params->lines,
+		/* we set an arbirary huge height for unknown height,
+		   GSaneScanner takes care of resizing at end of frame
+		   acquisition */
+		.height = (params->lines == -1 ? 65535 : params->lines),
 	};
 
 	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->process = gsane_processor_get_func(self);
 	g_return_val_if_fail(self->priv->process, NULL);
+
 	self->priv->format = gsane_processor_get_babl_format(self);
 	g_return_val_if_fail(self->priv->format, NULL);
 
@@ -186,26 +191,6 @@
 	self->priv->params = params;
 	self->priv->bytes_processed = 0;
 	self->priv->sample_offset = gsane_processor_get_sample_offset(self);
-	switch(params->format) {
-	case SANE_FRAME_GRAY:
-		g_debug("Processing GRAY frame format");
-		break;
-	case SANE_FRAME_RGB:
-		g_debug("Processing RGB frame format");
-		break;
-	case SANE_FRAME_RED:
-		g_debug("Processing RED frame format");
-		break;
-	case SANE_FRAME_GREEN:
-		g_debug("Processing GREEN frame format");
-		break;
-	case SANE_FRAME_BLUE:
-		g_debug("Processing BLUE frame format");
-		break;
-	default:
-		g_debug("Unknown frame format");
-		break;
-	}
 }
 
 void
@@ -247,12 +232,6 @@
 		}
 	}
 
-	/* extend buffer to fit if needed */
-	GeglRectangle *extent = g_boxed_copy(GEGL_TYPE_RECTANGLE, gegl_buffer_get_extent(self->priv->buffer));
-	extent->height = MAX(extent->height, self->priv->rect.y+self->priv->rect.height);
-	gegl_buffer_set_extent(self->priv->buffer, extent);
-	g_boxed_free(GEGL_TYPE_RECTANGLE, extent);
-
 	/* 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);

Modified: trunk/modules/gsane/gsane-scanner.c
==============================================================================
--- trunk/modules/gsane/gsane-scanner.c	(original)
+++ trunk/modules/gsane/gsane-scanner.c	Sat Dec 20 19:02:43 2008
@@ -49,13 +49,13 @@
 	guint image_count;
 	/* SANE frame paramters */
 	SANE_Parameters params;
+	guint chunk_len;
 	guint bytes_per_pixel;
+	guint frame_count;
 	/* total bytes read*/
 	volatile guint bytes_read;
 	/* total bytes to acquire to get the entire image (all frames) */
 	guint total_bytes_count;
-	/* status */
-	gboolean guessing_parameters;
 
 	/* Threads */
 	GThread* opt_thread;
@@ -86,7 +86,8 @@
 }
 
 
-/* Returns whether the status is good */
+/* Returns whether the status is good. Update node status if
+   failing. */
 static gboolean
 gsane_scanner_check_sane_status(GSaneScanner *self, const gchar* operation, SANE_Status status)
 {
@@ -98,6 +99,9 @@
 	return status == SANE_STATUS_GOOD;
 }
 
+/* Reload parameters. This is useful if we want to predetermine image
+   size and such. However, it is not supposed to be accurate before
+   sane_start() (see SANE standard). */
 static void
 gsane_scanner_reload_parameters_thread(GSaneScanner* self)
 {
@@ -111,9 +115,7 @@
 
 	g_debug("%s parameters reloaded", self->priv->sane_id);
 
- 	sane_cancel(self->priv->handle);
 	self->priv->params_thread = NULL;
-	self->priv->guessing_parameters = FALSE;
 }
 
 void
@@ -125,6 +127,8 @@
 	self->priv->params_thread = g_thread_create((GThreadFunc)gsane_scanner_reload_parameters_thread, self, FALSE, NULL);
 }
 
+/* Take care of one option, instanciating the right handler and
+   passing option to it. */
 static void
 gsane_scanner_handle_sane_option(GSaneScanner*self, SANE_Int n, const SANE_Option_Descriptor* desc, const gchar* group)
 {
@@ -144,9 +148,8 @@
 		key = g_type_name(handler_type);
 		handler = g_hash_table_lookup(self->priv->option_handlers, key);
 	}
-	else {
+	else
 		key = desc->name;
-	}
 
 	if (handler == NULL) {
 		handler = gsane_option_handler_new(handler_type, GNOME_SCAN_SCANNER(self), self->priv->handle);
@@ -159,8 +162,9 @@
 	g_type_class_unref(handler_class);
 }
 
-/* GThreadFunc */
-static void*
+/* Loops all SANE option and extract groups, sensors, buttons and
+   regular option. Let OptionHandler manager *all* options. */
+static void
 gsane_scanner_probe_options(GSaneScanner *self)
 {
 	SANE_Status status;
@@ -201,14 +205,18 @@
 		}
 	}
 
+	/* initialisation is done */
 	gnome_scan_node_update_status(GNOME_SCAN_NODE(self), GNOME_SCAN_STATUS_UNCONFIGURED, NULL);
+	/* this is where we know if we're actually ready. (well
+	   actually not until sane_start()â) */
 	gsane_scanner_reload_parameters(self);
 
  end:
 	self->priv->opt_thread = NULL;
-	return NULL;
 }
 
+/* Start counting images acquired during an atomic scan for mass
+   acquisition. */
 static void
 gsane_scanner_start_scan(GnomeScanNode *node)
 {
@@ -216,12 +224,14 @@
 	self->priv->image_count = 0;
 }
 
-static gboolean gsane_scanner_start_frame(GSaneScanner *self)
+/* Ask SANE to start a frame, update parameters according. We may need
+   to call sane_cancel() before each sane_start() in order to avoid
+   nasty SANE_STATUS_BUSY.  */
+static gboolean
+gsane_scanner_start_frame(GSaneScanner *self)
 {
 	SANE_Status status;
 
-	sane_cancel(self->priv->handle);
-
 	status = sane_start(self->priv->handle);
 	if (!gsane_scanner_check_sane_status(self, "sane_start", status))
 		return FALSE;
@@ -230,13 +240,18 @@
 	if (!gsane_scanner_check_sane_status(self, "sane_get_parameters", status))
 		return FALSE;
 
+	/* Scan line by line. We may compute larger chunk considering
+	   height. */
+	self->priv->chunk_len = self->priv->params.bytes_per_line;
 	gsane_processor_prepare_frame(&self->priv->processor, &self->priv->params);
 
-	g_debug("New frame started");
-
 	return TRUE;
 }
 
+/* returns the amount of frame to acquire to get all the image
+   data. Actually SANE tells use whether a frame is the last or
+   not. However we need frame count to handle proper sample handling,
+   progress monitoring, etc. */
 static guint
 gsane_scanner_get_frame_count(GSaneScanner *self)
 {
@@ -253,59 +268,98 @@
 	}
 }
 
+/* Starts the acquisition of one image of a scan. */
 static gboolean
 gsane_scanner_start_image(GnomeScanNode *node)
 {
 	GSaneScanner *self = GSANE_SCANNER(node);
 	GeglBuffer *buffer;
-	guint frame_count;
 
+	/* No mass acquisition from flatbed. We might use timeout scan, at this level? */
 	if (self->priv->image_count > 0 && !self->priv->is_adf_selected)
 		return FALSE;
 
+	/* start the frame */
 	if (!gsane_scanner_start_frame(self))
 		return FALSE;
 
-	frame_count = gsane_scanner_get_frame_count(self);
+	self->priv->frame_count = gsane_scanner_get_frame_count(self);
 	self->priv->bytes_read = 0;
 	self->priv->bytes_per_pixel = self->priv->params.bytes_per_line/self->priv->params.pixels_per_line;
-	self->priv->total_bytes_count = self->priv->params.pixels_per_line * self->priv->params.lines * frame_count;
+	self->priv->total_bytes_count = self->priv->params.pixels_per_line * self->priv->params.lines * self->priv->frame_count;
 
-	buffer = gsane_processor_prepare_image(&self->priv->processor, &self->priv->params, frame_count);
+	/* get the image buffer from the processor and let processor
+	   initialize data processing */
+	buffer = gsane_processor_prepare_image(&self->priv->processor, &self->priv->params, self->priv->frame_count);
 	gnome_scan_scanner_set_buffer((GnomeScanScanner*)self, buffer);
 
 	return TRUE;
 }
 
+/* Called once SANE stop sending data */
+static gboolean
+gsane_scanner_end_frame(GSaneScanner *self, SANE_Status status)
+{
+	g_debug("%s", sane_strstatus(status));
+	/* The frame is acquired */
+	if (status == SANE_STATUS_EOF) {
+		if (!self->priv->params.last_frame)
+			/* start next frame */
+			return gsane_scanner_start_frame(self);
+		else {
+			/* terminate hand scanner acquisition */
+			if (self->priv->params.lines == -1)
+				gsane_scanner_resize_buffer(self);
+			return FALSE; /* job done :). */
+		}
+	}
+	else
+		return FALSE; /* an error occur, just stop the work */
+}
+
+/* Resize buffer to actual size. This is needed for hand scanner where
+   we put an arbitrary huge height and then shrink back to the actual
+   height. */
+static void
+gsane_scanner_resize_buffer(GSaneScanner *self)
+{
+	GeglBuffer *buffer;
+	const GeglRectangle *extent;
+	GeglRectangle *actual_extent;
+	guint actual_height;
+
+	buffer = gnome_scan_scanner_get_buffer(GNOME_SCAN_SCANNER(self));
+	extent = gegl_buffer_get_extent(buffer);
+	actual_height = (self->priv->bytes_read/self->priv->frame_count) / self->priv->params.bytes_per_line;
+	actual_extent = g_boxed_copy(GEGL_TYPE_RECTANGLE, extent);
+	actual_extent->height = actual_height;
+	gegl_buffer_set_extent(buffer, actual_extent);
+	g_boxed_free(GEGL_TYPE_RECTANGLE, actual_extent);
+}
+
+/* Actually ask SANE data and work on it. */
 static gboolean
 gsane_scanner_work(GnomeScanScanner*scanner, gdouble *progress)
 {
-	GSaneScanner *self = GSANE_SCANNER(scanner);
+	GSaneScanner *self = (GSaneScanner*) scanner;
 	SANE_Status status;
 	SANE_Byte *buf;
 	SANE_Int read_len;
-	guint chunk_len = self->priv->params.bytes_per_line;
 
-	buf = g_new0(SANE_Byte, chunk_len);
-	status = sane_read (self->priv->handle, buf, chunk_len, &read_len);
-	if (status != SANE_STATUS_GOOD) {
-		g_debug("%s", sane_strstatus(status));
-		if (status == SANE_STATUS_EOF) {
-			if (!self->priv->params.last_frame)
-				/* start next frame */
-				return gsane_scanner_start_frame(self);
-			else
-				return FALSE;
-		}
-		else
-			return FALSE;
-	}
+	buf = g_new0(SANE_Byte, self->priv->chunk_len);
+	status = sane_read (self->priv->handle, buf, self->priv->chunk_len, &read_len);
+
+	if (status != SANE_STATUS_GOOD)
+		/* close current frame and start next if this is not
+		   the last frame of the image */
+		return gsane_scanner_end_frame(self, status);
 
 	self->priv->bytes_read += read_len;
-	g_debug("Asked %d bytes, got %d", chunk_len, read_len);
+	/* process the bytes received */
 	gsane_processor_process(&self->priv->processor, buf, read_len);
 	g_free(buf);
 
+	/* compute progress */
 	*progress = (gdouble)self->priv->bytes_read/(gdouble)self->priv->total_bytes_count;
 	return TRUE;
 }
@@ -314,6 +368,8 @@
 gsane_scanner_end_image(GnomeScanNode*scanner)
 {
 	GSaneScanner *self = GSANE_SCANNER(scanner);
+	/* Some backends needs to explicitely stop scan even after
+	   EOF. do we need this for each frame ? */
 	sane_cancel(self->priv->handle);
 	self->priv->image_count++;
 }
@@ -361,12 +417,6 @@
 }
 
 static void
-gsane_scanner_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
-{
-	G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
-}
-
-static void
 gsane_scanner_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 {
 	GSaneScanner *self;
@@ -393,7 +443,7 @@
 
 	o_class->constructor	= gsane_scanner_constructor;
 	o_class->finalize	= gsane_scanner_finalize;
-	o_class->get_property	= gsane_scanner_get_property;
+	/* there is no readable properties */
 	o_class->set_property	= gsane_scanner_set_property;
 	g_object_class_install_property(o_class, GSANE_SCANNER_SANE_ID, g_param_spec_string("sane-id", "SANE ID",  "SANE device id", NULL,G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property(o_class, GSANE_SCANNER_SANE_TYPE, g_param_spec_string("sane-type", "SANE Type", "SANE device type", NULL, G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));



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