[sane-devel] [RFC] [PATCH] scanadf [ -p | --pipe ] option

Rene Rebe rene@exactcode.de
Mon Jul 11 11:40:17 UTC 2005


This is a multi-part message in MIME format.
--------------020904010307030204030801
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit

Hi all,

for some high-speed scanning with on-the-fly format conversion or other 
post-processing it would be handy to pass the data to the scanadf script 
thru a pipe.

The attached patch implements this.

It also changes to wait(pid) for the script in any case as well as not 
ignore SIGCHLD - one of those interacted badly with my avision backend. 
I'll review the details before a possible commit.

Any comments?

Yours,

-- 
René Rebe - Rubensstr. 64 - 12157 Berlin (Europe / Germany)
             http://www.exactcode.de/ | http://www.t2-project.org/
             +49 (0)30  255 897 45


--------------020904010307030204030801
Content-Type: text/plain;
 name="scanadf.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="scanadf.patch"

diff -ur sane-frontends-1.0.13/doc/scanadf.man sane-frontends-1.0.13-adfmod/doc/scanadf.man
--- sane-frontends-1.0.13/doc/scanadf.man	2004-07-09 19:02:37.000000000 +0200
+++ sane-frontends-1.0.13-adfmod/doc/scanadf.man	2005-07-11 12:42:35.000000000 +0200
@@ -19,6 +19,7 @@
 .IR num ]
 .RB [ -e | --end-count
 .IR num ]
+.RB [ -p | --pipe ]
 .RB [ -r | --raw ]
 .RI [ device-specific-options ]
 .SH DESCRIPTION
@@ -191,6 +192,16 @@
 optional frame types and the default handling of unrecognized
 frametypes, this option becomes less and less useful.
 
+The
+.B -p
+or
+.B --pipe
+option allows passing the image date to the scan-script via a pipe
+rather than saving it to a file and executing the script thereafter.
+It might be useful for high-performance batch scans that should do
+post-processing, such as format convertion, on-the-fly.
+
+.PP
 As you might imagine, much of the power of
 .B scanadf
 comes from the fact that it can control any SANE backend.  Thus, the
@@ -242,6 +253,10 @@
 work at this time are:
 
 .RS
+.br
+.B sane-avision
+- Avision (and compatible) scanners. For batch scanning the --source "ADF",
+"ADF Rear" or "ADF Duplex" should be used.
 .br
 .B sane-bh
 - Bell+Howell Copiscan II series scanners.
diff -ur sane-frontends-1.0.13/src/scanadf.c sane-frontends-1.0.13-adfmod/src/scanadf.c
--- sane-frontends-1.0.13/src/scanadf.c	2004-07-09 19:03:16.000000000 +0200
+++ sane-frontends-1.0.13-adfmod/src/scanadf.c	2005-07-11 12:33:58.000000000 +0200
@@ -4,6 +4,7 @@
    scanimage by Andreas Beck and David Mosberger
 
    Copyright (C) 1999 Tom Martone
+   Copyright (C) 2005 Rene Rebe ([ -p | --pipe] script option)
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -39,6 +40,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 
 #include "sane/sane.h"
 #include "sane/sanei.h"
@@ -103,10 +105,11 @@
   { "end-count", required_argument, 0, 'e' },
   { "scan-script", required_argument, 0, 'S' },
   { "raw", no_argument, 0, 'r' },
+  { "pipe", no_argument, 0, 'p' },
   {0, }
 };
 
-#define BASE_OPTSTRING	"d:hLvVNTo:s:e:S:r"
+#define BASE_OPTSTRING	"d:hLvVNTo:s:e:S:pr"
 #define STRIP_HEIGHT	256	/* # lines we increment image height */
 
 static struct option * all_options;
@@ -872,8 +875,85 @@
   return res;
 }
 
+static int
+exec_script (const char *script, const char* fname, SANE_Bool use_pipe,
+             SANE_Parameters *parm, int *fd)
+{
+  static char cmd[PATH_MAX * 2];
+  static char env[6][PATH_MAX * 2];
+  int pid;
+  SANE_Int res;
+  SANE_Frame format;
+  extern char **environ;
+  int pipefd[2];
+
+  res = get_resolution(device);
+
+  format = parm->format;
+  if (format == SANE_FRAME_RED ||
+      format == SANE_FRAME_GREEN ||
+      format == SANE_FRAME_BLUE)
+  {
+     /* the resultant format is RGB */
+     format = SANE_FRAME_RGB;
+  }
+
+  sprintf(env[0], "SCAN_RES=%d", res); 
+  if (putenv(env[0])) 
+    fprintf(stderr, "putenv:failed\n");
+    sprintf(env[1], "SCAN_WIDTH=%d", parm->pixels_per_line);
+  if (putenv(env[1])) 
+    fprintf(stderr, "putenv:failed\n");
+    sprintf(env[2], "SCAN_HEIGHT=%d", parm->lines);
+  if (putenv(env[2])) 
+    fprintf(stderr, "putenv:failed\n");
+    sprintf(env[3], "SCAN_FORMAT_ID=%d", (int) parm->format);
+  if (putenv(env[3])) 
+    fprintf(stderr, "putenv:failed\n");
+    sprintf(env[4], "SCAN_FORMAT=%s", 
+            sane_strframe(parm->format));
+  if (putenv(env[4])) 
+      fprintf(stderr, "putenv:failed\n");
+  sprintf(env[5], "SCAN_DEPTH=%d", parm->depth);
+  if (putenv(env[5])) 
+    fprintf(stderr, "putenv:failed\n");
+
+  if (use_pipe) {
+    pipe(pipefd);
+  }
+
+  /*signal(SIGCHLD, SIG_IGN);*/
+  switch ((pid = fork())) 
+  {
+    case -1:	
+	/*  fork failed  */
+	fprintf(stderr, "Error forking: %s (%d)\n", strerror(errno), errno);
+	break;
+
+    case 0:
+	/*  in child process  */
+	if (use_pipe) {
+	 dup2(pipefd[0],0); close(pipefd[0]); close(pipefd[1]);
+	}
+	sprintf(cmd, "%s '%s'", script, fname);
+	execle(script, script, fname, NULL, environ);
+	exit(0);
+ 
+    default:
+	if (verbose) 
+	  fprintf(stderr, "Started script `%s' as pid=%d\n", script, pid);
+	break;
+  }
+  if (use_pipe) {
+    close(pipefd[0]);
+    *fd = pipefd[1];
+  }
+  return pid;
+}
+
 static SANE_Status
-scan_it_raw (const char *fname, SANE_Bool raw, const char *script)
+scan_it_raw (const char *fname, SANE_Bool raw, const char *script,
+             SANE_Bool use_pipe)
 {
   int i, len, first_frame = 1, offset = 0, must_buffer = 0;
   SANE_Byte buffer[32*1024], min = 0xff, max = 0;
@@ -881,6 +961,7 @@
   SANE_Status status;
   Image image = {0, };
   FILE *fp = NULL;
+  int pid = 0;
 
   do
     {
@@ -903,7 +984,15 @@
 	  goto cleanup;
 	}
 
-      fp = fopen(fname, "wb");
+      if (script && use_pipe)
+      {
+	int fd = 0;
+	pid = exec_script(script, fname, use_pipe, &parm, &fd);
+	fp = fdopen (fd, "wb");
+      }
+      else
+        fp = fopen(fname, "wb");
+
       if (!fp) {
 	fprintf(stderr, "Error opening output `%s': %s (%d)\n",
 		fname, strerror(errno), errno);
@@ -1144,65 +1233,16 @@
       fp = NULL;
     }
 
-  if (script) 
-    {
-      static char cmd[PATH_MAX * 2];
-      static char env[6][PATH_MAX * 2];
-      int pid;
-      SANE_Int res;
-      SANE_Frame format;
-      extern char **environ;
-
-      res = get_resolution(device);
-
-      format = parm.format;
-      if (format == SANE_FRAME_RED ||
-	  format == SANE_FRAME_GREEN ||
-	  format == SANE_FRAME_BLUE)
-	{
-	  /* the resultant format is RGB */
-	  format = SANE_FRAME_RGB;
-	}
-      sprintf(env[0], "SCAN_RES=%d", res); 
-      if (putenv(env[0])) 
-	fprintf(stderr, "putenv:failed\n");
-      sprintf(env[1], "SCAN_WIDTH=%d", parm.pixels_per_line);
-      if (putenv(env[1])) 
-	fprintf(stderr, "putenv:failed\n");
-      sprintf(env[2], "SCAN_HEIGHT=%d", parm.lines);
-      if (putenv(env[2])) 
-	fprintf(stderr, "putenv:failed\n");
-      sprintf(env[3], "SCAN_FORMAT_ID=%d", (int) parm.format);
-      if (putenv(env[3])) 
-	fprintf(stderr, "putenv:failed\n");
-      sprintf(env[4], "SCAN_FORMAT=%s", 
-	      sane_strframe(parm.format));
-      if (putenv(env[4])) 
-	fprintf(stderr, "putenv:failed\n");
-      sprintf(env[5], "SCAN_DEPTH=%d", parm.depth);
-      if (putenv(env[5])) 
-	fprintf(stderr, "putenv:failed\n");
-      signal(SIGCHLD, SIG_IGN);
-      switch ((pid = fork())) 
-	{
-	case -1:	
-	  /*  fork failed  */
-	  fprintf(stderr, "Error forking: %s (%d)\n", strerror(errno), errno);
-	  break;
+  if (script && !use_pipe)
+    pid = exec_script (script, fname, use_pipe, &parm, NULL);
 
-	case 0:
-	  /*  in child process  */
-	  sprintf(cmd, "%s '%s'", script, fname);
-	  /*	  system(cmd); */
-	  execle(script, script, fname, NULL, environ);
-	  exit(0);
-      
-	default:
-	  if (verbose) 
-	    fprintf(stderr, "Started script `%s' as pid=%d\n", script, pid);
-	  break;
-	}
-    }
+  if (script) {
+    int exit_status = 0;
+    waitpid (pid, &exit_status, 0);
+    if (exit_status && verbose)
+      fprintf(stderr, "%s: WARNING: child exited with %d\n",
+              prog_name, exit_status);
+  }
 
 cleanup:
   if (image.data)
@@ -1213,7 +1253,8 @@
 }
 
 static SANE_Int 
-scan_docs (int start, int end, int no_overwrite, SANE_Bool raw, const char *outfmt, const char *script)
+scan_docs (int start, int end, int no_overwrite, SANE_Bool raw,
+           const char *outfmt, const char *script, SANE_Bool use_pipe)
 {
   SANE_Status status = SANE_STATUS_GOOD;
   SANE_Int scannedPages = 0;
@@ -1223,8 +1264,7 @@
 
   while (end < 0 || start <= end) 
     {
-      /*!!! buffer overflow; need protection */
-      sprintf(fname, outfmt, start);
+      snprintf(fname, sizeof (fname), outfmt, start);
 
       /* does the filename already exist? */
       if (no_overwrite) 
@@ -1239,7 +1279,7 @@
       
       /* Scan the document */
       if (status == SANE_STATUS_GOOD) 
-	status = scan_it_raw(fname, raw, script);
+	status = scan_it_raw(fname, raw, script, use_pipe);
 
       /* Any scan errors? */
       if (status == SANE_STATUS_NO_DOCS) 
@@ -1280,6 +1320,7 @@
   SANE_Status status;
   char *full_optstring;
   SANE_Bool raw = SANE_FALSE;
+  SANE_Bool use_pipe = SANE_FALSE;
   const char *scanScript = NULL;		/* script to run at end of scan */
   const char *outputFile = "image-%04d";	/* file name(format) to write output to */
   int startNum = 1, endNum = -1;		/* start/end numbers of pages to scan */
@@ -1338,6 +1379,7 @@
 	case 's': startNum = atoi(optarg); break;
 	case 'e': endNum = atoi(optarg); break;
 	case 'r': raw = SANE_TRUE; break;
+	case 'p': use_pipe = SANE_TRUE; break;
 
 	case 'V':
 	  printf ("scanadf (%s) %s\n", PACKAGE, VERSION);
@@ -1455,7 +1497,7 @@
 	      exit (1);	/* error message is printed by getopt_long() */
 
 	    case 'd': case 'h': case 'v': case 'V': case 'T':
-	    case 'o': case 'S': case 's': case 'e': case 'r':
+	    case 'o': case 'S': case 's': case 'e': case 'p': case 'r':
 
 	      /* previously handled options */
 	      break;
@@ -1569,7 +1611,8 @@
   signal (SIGPIPE, sighandler);
   signal (SIGTERM, sighandler);
 
-  status = scan_docs (startNum, endNum, no_overwrite, raw, outputFile, scanScript);
+  status = scan_docs (startNum, endNum, no_overwrite, raw,
+                      outputFile, scanScript, use_pipe);
 
   sane_cancel (device);
   sane_close (device);

--------------020904010307030204030801--




More information about the sane-devel mailing list