diff --git a/Changelog b/Changelog index a9a3762..20a56fc 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,10 @@ + +2005-12-04 Rene Rebe + + * src/scanadf.c doc/scanadf.man: Added -p, --pipe option to scanadf + to pass data to the scripts via stdin and thus process the image + data parallel to the scan. + 2005-10-09 Henning Meier-Geinitz * configure configure.in: Changed version to 1.0.14-cvs. diff --git a/doc/scanadf.man b/doc/scanadf.man index f20243e..8210c64 100644 --- a/doc/scanadf.man +++ b/doc/scanadf.man @@ -20,6 +20,7 @@ scanadf - acquire multiple images from a scanner equipped with an ADF .IR num ] .RB [ -e | --end-count .IR num ] +.RB [ -p | --pipe ] .RB [ -r | --raw ] .RI [ device-specific-options ] .SH DESCRIPTION @@ -158,6 +159,9 @@ information about the parameters of the image. .B SCAN_FORMAT_ID - the numeric image format identifier .br +.B SCAN_PIPE +- non-zero if a pipe is used for data transfer (instead of files) +.br .RE .PP @@ -199,6 +203,16 @@ the file to a more useful format. NOTE: With support for the 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 @@ -251,6 +265,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. .br diff --git a/src/scanadf.c b/src/scanadf.c index d4ff566..a9e604c 100644 --- a/src/scanadf.c +++ b/src/scanadf.c @@ -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 @@ -105,10 +106,11 @@ static struct option basic_options[] = { "scan-script", required_argument, 0, 'S' }, { "script-wait", no_argument, 0, 128 }, { "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; @@ -875,8 +877,89 @@ get_resolution(SANE_Device *device) 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[7][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"); + sprintf(env[6], "SCAN_PIPE=%d", use_pipe); + if (putenv(env[6])) + 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; @@ -884,6 +967,7 @@ scan_it_raw (const char *fname, SANE_Bool raw, const char *script) SANE_Status status; Image image = {0, }; FILE *fp = NULL; + int pid = 0; do { @@ -906,7 +990,15 @@ scan_it_raw (const char *fname, SANE_Bool raw, const char *script) 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); @@ -1147,65 +1239,16 @@ scan_it_raw (const char *fname, SANE_Bool raw, const char *script) 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; + if (script && !use_pipe) + pid = exec_script (script, fname, use_pipe, &parm, NULL); - 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; - - 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) @@ -1216,7 +1259,8 @@ cleanup: } 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; @@ -1226,8 +1270,7 @@ scan_docs (int start, int end, int no_overwrite, SANE_Bool raw, const char *outf 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) @@ -1242,7 +1285,7 @@ scan_docs (int start, int end, int no_overwrite, SANE_Bool raw, const char *outf /* 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) @@ -1283,6 +1326,7 @@ main (int argc, char **argv) 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 */ int scriptWait = 0; const char *outputFile = "image-%04d"; /* file name(format) to write output to */ @@ -1343,6 +1387,7 @@ main (int argc, char **argv) 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); @@ -1463,7 +1508,7 @@ main (int argc, char **argv) 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; @@ -1577,7 +1622,8 @@ List of available devices:", prog_name); 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);