summaryrefslogtreecommitdiff
path: root/frontend/scanimage.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/scanimage.c')
-rw-r--r--frontend/scanimage.c212
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;