diff options
Diffstat (limited to 'frontend/scanimage.c')
-rw-r--r-- | frontend/scanimage.c | 212 |
1 files changed, 149 insertions, 63 deletions
diff --git a/frontend/scanimage.c b/frontend/scanimage.c index fe02750..ae65ebf 100644 --- a/frontend/scanimage.c +++ b/frontend/scanimage.c @@ -2,7 +2,7 @@ Uses the SANE library. Copyright (C) 2015 Rolf Bensch <rolf at bensch hyphen online dot de> Copyright (C) 1996, 1997, 1998 Andreas Beck and David Mosberger - + Copyright (C) 1999 - 2009 by the SANE Project -- See AUTHORS and ChangeLog for details. @@ -32,6 +32,7 @@ #include <assert.h> #include "lgetopt.h" +#include <inttypes.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -93,6 +94,7 @@ static struct option basic_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"progress", no_argument, NULL, 'p'}, + {"output-file", required_argument, NULL, 'o'}, {"test", no_argument, NULL, 'T'}, {"all-options", no_argument, NULL, 'A'}, {"version", no_argument, NULL, 'V'}, @@ -111,12 +113,13 @@ static struct option basic_options[] = { {0, 0, NULL, 0} }; -#define OUTPUT_PNM 0 -#define OUTPUT_TIFF 1 -#define OUTPUT_PNG 2 -#define OUTPUT_JPEG 3 +#define OUTPUT_UNKNOWN 0 +#define OUTPUT_PNM 1 +#define OUTPUT_TIFF 2 +#define OUTPUT_PNG 3 +#define OUTPUT_JPEG 4 -#define BASE_OPTSTRING "d:hi:Lf:B::nvVTAbp" +#define BASE_OPTSTRING "d:hi:Lf:o:B::nvVTAbp" #define STRIP_HEIGHT 256 /* # lines we increment image height */ static struct option *all_options; @@ -125,9 +128,10 @@ static int *option_number; static SANE_Handle device; static int verbose; static int progress = 0; +static const char* output_file = NULL; static int test; static int all; -static int output_format = OUTPUT_PNM; +static int output_format = OUTPUT_UNKNOWN; static int help; static int dont_scan = 0; static const char *prog_name; @@ -201,51 +205,30 @@ auth_callback (SANE_String_Const resource, if ((strlen (tmp) > 0) && (tmp[strlen (tmp) - 1] == '\r')) tmp[strlen (tmp) - 1] = 0; - if (strchr (tmp, ':') != NULL) + char *colon1 = strchr (tmp, ':'); + if (colon1 != NULL) { + char *tmp_username = tmp; + *colon1 = '\0'; - if (strchr (strchr (tmp, ':') + 1, ':') != NULL) + char *colon2 = strchr (colon1 + 1, ':'); + if (colon2 != NULL) { + char *tmp_password = colon1 + 1; + *colon2 = '\0'; - if ((strncmp - (strchr (strchr (tmp, ':') + 1, ':') + 1, - resource, len) == 0) - && - ((int) strlen - (strchr (strchr (tmp, ':') + 1, ':') + 1) == - len)) + if ((strncmp (colon2 + 1, resource, len) == 0) + && ((int) strlen (colon2 + 1) == len)) { - - if ((strchr (tmp, ':') - tmp) < - SANE_MAX_USERNAME_LEN) - { - - if ((strchr (strchr (tmp, ':') + 1, ':') - - (strchr (tmp, ':') + 1)) < - SANE_MAX_PASSWORD_LEN) - { - - strncpy (username, tmp, - strchr (tmp, ':') - tmp); - - username[strchr (tmp, ':') - tmp] = 0; - - strncpy (password, - strchr (tmp, ':') + 1, - strchr (strchr (tmp, ':') + 1, - ':') - - (strchr (tmp, ':') + 1)); - password[strchr - (strchr (tmp, ':') + 1, - ':') - (strchr (tmp, - ':') + 1)] = - 0; - - query_user = 0; - break; - } - } - + if ((strlen (tmp_username) < SANE_MAX_USERNAME_LEN) && + (strlen (tmp_password) < SANE_MAX_PASSWORD_LEN)) + { + strncpy (username, tmp_username, SANE_MAX_USERNAME_LEN); + strncpy (password, tmp_password, SANE_MAX_PASSWORD_LEN); + + query_user = 0; + break; + } } } } @@ -403,7 +386,7 @@ print_option (SANE_Device * device, int opt_num, const SANE_Option_Descriptor *o }*/ /* if one of these three is not set, option is useless, skip it */ - if(!(opt->cap & + if(!(opt->cap & (SANE_CAP_SOFT_SELECT | SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT) )){ return; @@ -462,7 +445,7 @@ print_option (SANE_Device * device, int opt_num, const SANE_Option_Descriptor *o if (!strcmp (opt->name, "x")) { printf ("%d..%d", - opt->constraint.range->min, + opt->constraint.range->min, opt->constraint.range->max - tl_x); } else if (!strcmp (opt->name, "y")) @@ -1011,7 +994,7 @@ set_option (SANE_Handle device, int optnum, void *valuep) prog_name, opt->name); return; } - + if (opt->size == sizeof (SANE_Word) && opt->type != SANE_TYPE_STRING) orig = *(SANE_Word *) valuep; @@ -1314,7 +1297,8 @@ advance (Image * image) static SANE_Status scan_it (FILE *ofp) { - int i, len, first_frame = 1, offset = 0, must_buffer = 0, hundred_percent; + int i, len, first_frame = 1, offset = 0, must_buffer = 0; + uint64_t hundred_percent = 0; SANE_Byte min = 0xff, max = 0; SANE_Parameters parm; SANE_Status status; @@ -1322,7 +1306,7 @@ scan_it (FILE *ofp) static const char *format_name[] = { "gray", "RGB", "red", "green", "blue" }; - SANE_Word total_bytes = 0, expected_bytes; + uint64_t total_bytes = 0, expected_bytes; SANE_Int hang_over = -1; #ifdef HAVE_LIBPNG int pngrow = 0; @@ -1483,7 +1467,7 @@ scan_it (FILE *ofp) offset = parm.format - SANE_FRAME_RED; image.x = image.y = 0; } - hundred_percent = parm.bytes_per_line * parm.lines + hundred_percent = ((uint64_t)parm.bytes_per_line) * parm.lines * ((parm.format == SANE_FRAME_RGB || parm.format == SANE_FRAME_GRAY) ? 1:3); while (1) @@ -1495,7 +1479,12 @@ scan_it (FILE *ofp) if (progr > 100.) progr = 100.; if (progress) - fprintf (stderr, "Progress: %3.1f%%\r", progr); + { + if (parm.lines >= 0) + fprintf(stderr, "Progress: %3.1f%%\r", progr); + else + fprintf(stderr, "Progress: (unknown)\r"); + } if (status != SANE_STATUS_GOOD) { @@ -1757,7 +1746,7 @@ cleanup: free (image.data); - expected_bytes = parm.bytes_per_line * parm.lines * + expected_bytes = ((uint64_t)parm.bytes_per_line) * parm.lines * ((parm.format == SANE_FRAME_RGB || parm.format == SANE_FRAME_GRAY) ? 1 : 3); if (parm.lines < 0) @@ -1766,10 +1755,10 @@ cleanup: { fprintf (stderr, "%s: WARNING: read more data than announced by backend " - "(%u/%u)\n", prog_name, total_bytes, expected_bytes); + "(%" PRIu64 "/%" PRIu64 ")\n", prog_name, total_bytes, expected_bytes); } else if (verbose) - fprintf (stderr, "%s: read %u bytes in total\n", prog_name, total_bytes); + fprintf (stderr, "%s: read %" PRIu64 " bytes in total\n", prog_name, total_bytes); return status; } @@ -1968,6 +1957,43 @@ static void print_options(SANE_Device * device, SANE_Int num_dev_options, SANE_B fputc ('\n', stdout); } +static int guess_output_format(const char* output_file) +{ + if (output_file == NULL) + { + fprintf(stderr, "Output format is not set, using pnm as a default.\n"); + return OUTPUT_PNM; + } + + // if the user passes us a path with a known extension then he won't be surprised if we figure + // out correct --format option. No warning is necessary in that case. + const char* extension = strrchr(output_file, '.'); + if (extension != NULL) + { + struct { + const char* extension; + int output_format; + } formats[] = { + { ".pnm", OUTPUT_PNM }, + { ".png", OUTPUT_PNG }, + { ".jpg", OUTPUT_JPEG }, + { ".jpeg", OUTPUT_JPEG }, + { ".tiff", OUTPUT_TIFF }, + { ".tif", OUTPUT_TIFF } + }; + for (unsigned i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) + { + if (strcmp(extension, formats[i].extension) == 0) + return formats[i].output_format; + } + } + + // it would be very confusing if user makes a typo in the filename and the output format changes. + // This is most likely not what the user wanted. + fprintf(stderr, "Could not guess output format from the given path and no --format given.\n"); + exit(1); +} + int main (int argc, char **argv) { @@ -2033,6 +2059,9 @@ main (int argc, char **argv) case 'p': progress = 1; break; + case 'o': + output_file = optarg; + break; case 'B': if (optarg) buffer_size = 1024 * atoi(optarg); @@ -2088,8 +2117,23 @@ main (int argc, char **argv) exit(1); #endif } - else - output_format = OUTPUT_PNM; + else if (strcmp (optarg, "pnm") == 0) + { + output_format = OUTPUT_PNM; + } + else + { + fprintf(stderr, "Unknown output image format '%s'.\n", optarg); + fprintf(stderr, "Supported formats: pnm, tiff"); +#ifdef HAVE_LIBPNG + fprintf(stderr, ", png"); +#endif +#ifdef HAVE_LIBJPEG + fprintf(stderr, ", jpeg"); +#endif + fprintf(stderr, ".\n"); + exit(1); + } break; case OPTION_MD5: accept_only_md5_auth = 1; @@ -2202,15 +2246,15 @@ main (int argc, char **argv) if (defdevname) printf ("default device is `%s'\n", defdevname); scanimage_exit (0); + break; } - case 'V': printf ("scanimage (%s) %s; backend version %d.%d.%d\n", PACKAGE, VERSION, SANE_VERSION_MAJOR (version_code), SANE_VERSION_MINOR (version_code), SANE_VERSION_BUILD (version_code)); scanimage_exit (0); - + break; default: break; /* ignore device specific options for now */ } @@ -2235,7 +2279,8 @@ Parameters are separated by a blank from single-character options (e.g.\n\ %%m (model), %%t (type), %%i (index number), and\n\ %%n (newline)\n\ -b, --batch[=FORMAT] working in batch mode, FORMAT is `out%%d.pnm' `out%%d.tif'\n\ - `out%%d.png' or `out%%d.jpg' by default depending on --format\n"); + `out%%d.png' or `out%%d.jpg' by default depending on --format\n\ + This option is incompatible with --output-file."); printf ("\ --batch-start=# page number to start naming files with\n\ --batch-count=# how many pages to scan in batch mode\n\ @@ -2247,6 +2292,8 @@ Parameters are separated by a blank from single-character options (e.g.\n\ printf ("\ --accept-md5-only only accept authorization requests using md5\n\ -p, --progress print progress messages\n\ +-o, --output-file=PATH save output to the given file instead of stdout.\n\ + This option is incompatible with --batch.\n\ -n, --dont-scan only set options, don't actually scan\n\ -T, --test test backend thoroughly\n\ -A, --all-options list all available backend options\n\ @@ -2257,6 +2304,15 @@ Parameters are separated by a blank from single-character options (e.g.\n\ -V, --version print version information\n"); } + if (batch && output_file != NULL) + { + fprintf(stderr, "--batch and --output-file can't be used together.\n"); + exit(1); + } + + if (output_format == OUTPUT_UNKNOWN) + output_format = guess_output_format(output_file); + if (!devname) { /* If no device name was specified explicitly, we look at the @@ -2389,6 +2445,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\ case 'd': case 'h': case 'p': + case 'o': case 'v': case 'V': case 'T': @@ -2535,7 +2592,19 @@ List of available devices:", prog_name); } if (!batch) - ofp = stdout; + { + ofp = stdout; + if (output_file != NULL) + { + ofp = fopen(output_file, "w"); + if (ofp == NULL) + { + fprintf(stderr, "%s: could not open input file '%s', " + "exiting\n", prog_name, output_file); + scanimage_exit(1); + } + } + } if (batch) { @@ -2662,6 +2731,14 @@ List of available devices:", prog_name); } } } + else + { + if (output_file && ofp) + { + fclose(ofp); + ofp = NULL; + } + } break; default: if (batch) @@ -2673,6 +2750,15 @@ List of available devices:", prog_name); } unlink (part_path); } + else + { + if (output_file && ofp) + { + fclose(ofp); + ofp = NULL; + } + unlink (output_file); + } break; } /* switch */ n += batch_increment; |