1141cc406Sopenharmony_ci/* scanimage -- command line scanning utility 2141cc406Sopenharmony_ci Uses the SANE library. 3141cc406Sopenharmony_ci Copyright (C) 2015 Rolf Bensch <rolf at bensch hyphen online dot de> 4141cc406Sopenharmony_ci Copyright (C) 1996, 1997, 1998 Andreas Beck and David Mosberger 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci Copyright (C) 1999 - 2009 by the SANE Project -- See AUTHORS and ChangeLog 7141cc406Sopenharmony_ci for details. 8141cc406Sopenharmony_ci 9141cc406Sopenharmony_ci For questions and comments contact the sane-devel mailinglist (see 10141cc406Sopenharmony_ci http://www.sane-project.org/mailing-lists.html). 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 13141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 14141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 15141cc406Sopenharmony_ci License, or (at your option) any later version. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 18141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 19141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20141cc406Sopenharmony_ci General Public License for more details. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 23141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 24141cc406Sopenharmony_ci*/ 25141cc406Sopenharmony_ci 26141cc406Sopenharmony_ci#ifdef _AIX 27141cc406Sopenharmony_ci# include "../include/lalloca.h" /* MUST come first for AIX! */ 28141cc406Sopenharmony_ci#endif 29141cc406Sopenharmony_ci 30141cc406Sopenharmony_ci#include "../include/sane/config.h" 31141cc406Sopenharmony_ci#include "../include/lalloca.h" 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci#include <assert.h> 34141cc406Sopenharmony_ci#include "lgetopt.h" 35141cc406Sopenharmony_ci#include <inttypes.h> 36141cc406Sopenharmony_ci#include <signal.h> 37141cc406Sopenharmony_ci#include <stdio.h> 38141cc406Sopenharmony_ci#include <stdlib.h> 39141cc406Sopenharmony_ci#include <string.h> 40141cc406Sopenharmony_ci#include <unistd.h> 41141cc406Sopenharmony_ci#include <stdarg.h> 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci#ifdef __FreeBSD__ 44141cc406Sopenharmony_ci#include <libgen.h> 45141cc406Sopenharmony_ci#endif 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci#if defined (__APPLE__) && defined (__MACH__) 48141cc406Sopenharmony_ci#include <libgen.h> // for basename() 49141cc406Sopenharmony_ci#endif 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ci#include <sys/types.h> 52141cc406Sopenharmony_ci#include <sys/stat.h> 53141cc406Sopenharmony_ci 54141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 55141cc406Sopenharmony_ci#include <png.h> 56141cc406Sopenharmony_ci#endif 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 59141cc406Sopenharmony_ci#include <jpeglib.h> 60141cc406Sopenharmony_ci#endif 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci#include "../include/_stdint.h" 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ci#include "../include/sane/sane.h" 65141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 66141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ci#include "sicc.h" 69141cc406Sopenharmony_ci#include "stiff.h" 70141cc406Sopenharmony_ci 71141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 72141cc406Sopenharmony_ci#include "jpegtopdf.h" 73141cc406Sopenharmony_ci#endif 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci#include "../include/md5.h" 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci#ifndef PATH_MAX 78141cc406Sopenharmony_ci#define PATH_MAX 1024 79141cc406Sopenharmony_ci#endif 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_citypedef struct 82141cc406Sopenharmony_ci{ 83141cc406Sopenharmony_ci uint8_t *data; 84141cc406Sopenharmony_ci int width; /*WARNING: this is in bytes, get pixel width from param*/ 85141cc406Sopenharmony_ci int height; 86141cc406Sopenharmony_ci int x; 87141cc406Sopenharmony_ci int y; 88141cc406Sopenharmony_ci int num_channels; 89141cc406Sopenharmony_ci} 90141cc406Sopenharmony_ciImage; 91141cc406Sopenharmony_ci 92141cc406Sopenharmony_ci#define OPTION_FORMAT 1001 93141cc406Sopenharmony_ci#define OPTION_MD5 1002 94141cc406Sopenharmony_ci#define OPTION_BATCH_COUNT 1003 95141cc406Sopenharmony_ci#define OPTION_BATCH_START_AT 1004 96141cc406Sopenharmony_ci#define OPTION_BATCH_DOUBLE 1005 97141cc406Sopenharmony_ci#define OPTION_BATCH_INCREMENT 1006 98141cc406Sopenharmony_ci#define OPTION_BATCH_PROMPT 1007 99141cc406Sopenharmony_ci#define OPTION_BATCH_PRINT 1008 100141cc406Sopenharmony_ci 101141cc406Sopenharmony_ci#define BATCH_COUNT_UNLIMITED -1 102141cc406Sopenharmony_ci 103141cc406Sopenharmony_cistatic struct option basic_options[] = { 104141cc406Sopenharmony_ci {"device-name", required_argument, NULL, 'd'}, 105141cc406Sopenharmony_ci {"list-devices", no_argument, NULL, 'L'}, 106141cc406Sopenharmony_ci {"formatted-device-list", required_argument, NULL, 'f'}, 107141cc406Sopenharmony_ci {"help", no_argument, NULL, 'h'}, 108141cc406Sopenharmony_ci {"verbose", no_argument, NULL, 'v'}, 109141cc406Sopenharmony_ci {"progress", no_argument, NULL, 'p'}, 110141cc406Sopenharmony_ci {"output-file", required_argument, NULL, 'o'}, 111141cc406Sopenharmony_ci {"test", no_argument, NULL, 'T'}, 112141cc406Sopenharmony_ci {"all-options", no_argument, NULL, 'A'}, 113141cc406Sopenharmony_ci {"version", no_argument, NULL, 'V'}, 114141cc406Sopenharmony_ci {"buffer-size", optional_argument, NULL, 'B'}, 115141cc406Sopenharmony_ci {"batch", optional_argument, NULL, 'b'}, 116141cc406Sopenharmony_ci {"batch-count", required_argument, NULL, OPTION_BATCH_COUNT}, 117141cc406Sopenharmony_ci {"batch-start", required_argument, NULL, OPTION_BATCH_START_AT}, 118141cc406Sopenharmony_ci {"batch-double", no_argument, NULL, OPTION_BATCH_DOUBLE}, 119141cc406Sopenharmony_ci {"batch-increment", required_argument, NULL, OPTION_BATCH_INCREMENT}, 120141cc406Sopenharmony_ci {"batch-print", no_argument, NULL, OPTION_BATCH_PRINT}, 121141cc406Sopenharmony_ci {"batch-prompt", no_argument, NULL, OPTION_BATCH_PROMPT}, 122141cc406Sopenharmony_ci {"format", required_argument, NULL, OPTION_FORMAT}, 123141cc406Sopenharmony_ci {"accept-md5-only", no_argument, NULL, OPTION_MD5}, 124141cc406Sopenharmony_ci {"icc-profile", required_argument, NULL, 'i'}, 125141cc406Sopenharmony_ci {"dont-scan", no_argument, NULL, 'n'}, 126141cc406Sopenharmony_ci {0, 0, NULL, 0} 127141cc406Sopenharmony_ci}; 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci#define OUTPUT_UNKNOWN 0 130141cc406Sopenharmony_ci#define OUTPUT_PNM 1 131141cc406Sopenharmony_ci#define OUTPUT_TIFF 2 132141cc406Sopenharmony_ci#define OUTPUT_PNG 3 133141cc406Sopenharmony_ci#define OUTPUT_JPEG 4 134141cc406Sopenharmony_ci#define OUTPUT_PDF 5 135141cc406Sopenharmony_ci 136141cc406Sopenharmony_ci#define BASE_OPTSTRING "d:hi:Lf:o:B::nvVTAbp" 137141cc406Sopenharmony_ci#define STRIP_HEIGHT 256 /* # lines we increment image height */ 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_cistatic struct option *all_options; 140141cc406Sopenharmony_cistatic int option_number_len; 141141cc406Sopenharmony_cistatic int *option_number; 142141cc406Sopenharmony_cistatic SANE_Handle device; 143141cc406Sopenharmony_cistatic int verbose; 144141cc406Sopenharmony_cistatic int progress = 0; 145141cc406Sopenharmony_cistatic const char* output_file = NULL; 146141cc406Sopenharmony_cistatic int test; 147141cc406Sopenharmony_cistatic int all; 148141cc406Sopenharmony_cistatic int output_format = OUTPUT_UNKNOWN; 149141cc406Sopenharmony_cistatic int help; 150141cc406Sopenharmony_cistatic int dont_scan = 0; 151141cc406Sopenharmony_cistatic const char *prog_name; 152141cc406Sopenharmony_cistatic int resolution_optind = -1, resolution_value = 0; 153141cc406Sopenharmony_ci 154141cc406Sopenharmony_ci/* window (area) related options */ 155141cc406Sopenharmony_cistatic SANE_Option_Descriptor window_option[4]; /*updated descs for x,y,l,t*/ 156141cc406Sopenharmony_cistatic int window[4]; /*index into backend options for x,y,l,t*/ 157141cc406Sopenharmony_cistatic SANE_Word window_val[2]; /*the value for x,y options*/ 158141cc406Sopenharmony_cistatic int window_val_user[2]; /* is x,y user-specified? */ 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_cistatic int accept_only_md5_auth = 0; 161141cc406Sopenharmony_cistatic const char *icc_profile = NULL; 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_cistatic void fetch_options (SANE_Device * device); 164141cc406Sopenharmony_cistatic void scanimage_exit (int); 165141cc406Sopenharmony_ci 166141cc406Sopenharmony_cistatic SANE_Word tl_x = 0; 167141cc406Sopenharmony_cistatic SANE_Word tl_y = 0; 168141cc406Sopenharmony_cistatic SANE_Word br_x = 0; 169141cc406Sopenharmony_cistatic SANE_Word br_y = 0; 170141cc406Sopenharmony_cistatic SANE_Byte *buffer; 171141cc406Sopenharmony_cistatic size_t buffer_size; 172141cc406Sopenharmony_ci 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_cistatic void 175141cc406Sopenharmony_ciauth_callback (SANE_String_Const resource, 176141cc406Sopenharmony_ci SANE_Char * username, SANE_Char * password) 177141cc406Sopenharmony_ci{ 178141cc406Sopenharmony_ci char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN], *wipe; 179141cc406Sopenharmony_ci unsigned char md5digest[16]; 180141cc406Sopenharmony_ci int md5mode = 0, len, query_user = 1; 181141cc406Sopenharmony_ci FILE *pass_file; 182141cc406Sopenharmony_ci struct stat stat_buf; 183141cc406Sopenharmony_ci char * uname = NULL; 184141cc406Sopenharmony_ci 185141cc406Sopenharmony_ci *tmp = 0; 186141cc406Sopenharmony_ci 187141cc406Sopenharmony_ci if (getenv ("HOME") != NULL) 188141cc406Sopenharmony_ci { 189141cc406Sopenharmony_ci if (strlen (getenv ("HOME")) < 500) 190141cc406Sopenharmony_ci { 191141cc406Sopenharmony_ci sprintf (tmp, "%s/.sane/pass", getenv ("HOME")); 192141cc406Sopenharmony_ci } 193141cc406Sopenharmony_ci } 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci if ((strlen (tmp) > 0) && (stat (tmp, &stat_buf) == 0)) 196141cc406Sopenharmony_ci { 197141cc406Sopenharmony_ci 198141cc406Sopenharmony_ci if ((stat_buf.st_mode & 63) != 0) 199141cc406Sopenharmony_ci { 200141cc406Sopenharmony_ci fprintf (stderr, "%s has wrong permissions (use at least 0600)\n", 201141cc406Sopenharmony_ci tmp); 202141cc406Sopenharmony_ci } 203141cc406Sopenharmony_ci else 204141cc406Sopenharmony_ci { 205141cc406Sopenharmony_ci 206141cc406Sopenharmony_ci if ((pass_file = fopen (tmp, "r")) != NULL) 207141cc406Sopenharmony_ci { 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci if (strstr (resource, "$MD5$") != NULL) 210141cc406Sopenharmony_ci len = (strstr (resource, "$MD5$") - resource); 211141cc406Sopenharmony_ci else 212141cc406Sopenharmony_ci len = strlen (resource); 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_ci while (fgets (tmp, sizeof(tmp), pass_file)) 215141cc406Sopenharmony_ci { 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci if ((strlen (tmp) > 0) && (tmp[strlen (tmp) - 1] == '\n')) 218141cc406Sopenharmony_ci tmp[strlen (tmp) - 1] = 0; 219141cc406Sopenharmony_ci if ((strlen (tmp) > 0) && (tmp[strlen (tmp) - 1] == '\r')) 220141cc406Sopenharmony_ci tmp[strlen (tmp) - 1] = 0; 221141cc406Sopenharmony_ci 222141cc406Sopenharmony_ci char *colon1 = strchr (tmp, ':'); 223141cc406Sopenharmony_ci if (colon1 != NULL) 224141cc406Sopenharmony_ci { 225141cc406Sopenharmony_ci char *tmp_username = tmp; 226141cc406Sopenharmony_ci *colon1 = '\0'; 227141cc406Sopenharmony_ci 228141cc406Sopenharmony_ci char *colon2 = strchr (colon1 + 1, ':'); 229141cc406Sopenharmony_ci if (colon2 != NULL) 230141cc406Sopenharmony_ci { 231141cc406Sopenharmony_ci char *tmp_password = colon1 + 1; 232141cc406Sopenharmony_ci *colon2 = '\0'; 233141cc406Sopenharmony_ci 234141cc406Sopenharmony_ci if ((strncmp (colon2 + 1, resource, len) == 0) 235141cc406Sopenharmony_ci && ((int) strlen (colon2 + 1) == len)) 236141cc406Sopenharmony_ci { 237141cc406Sopenharmony_ci if ((strlen (tmp_username) < SANE_MAX_USERNAME_LEN) && 238141cc406Sopenharmony_ci (strlen (tmp_password) < SANE_MAX_PASSWORD_LEN)) 239141cc406Sopenharmony_ci { 240141cc406Sopenharmony_ci strncpy (username, tmp_username, SANE_MAX_USERNAME_LEN); 241141cc406Sopenharmony_ci strncpy (password, tmp_password, SANE_MAX_PASSWORD_LEN); 242141cc406Sopenharmony_ci 243141cc406Sopenharmony_ci query_user = 0; 244141cc406Sopenharmony_ci break; 245141cc406Sopenharmony_ci } 246141cc406Sopenharmony_ci } 247141cc406Sopenharmony_ci } 248141cc406Sopenharmony_ci } 249141cc406Sopenharmony_ci } 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_ci fclose (pass_file); 252141cc406Sopenharmony_ci } 253141cc406Sopenharmony_ci } 254141cc406Sopenharmony_ci } 255141cc406Sopenharmony_ci 256141cc406Sopenharmony_ci if (strstr (resource, "$MD5$") != NULL) 257141cc406Sopenharmony_ci { 258141cc406Sopenharmony_ci md5mode = 1; 259141cc406Sopenharmony_ci len = (strstr (resource, "$MD5$") - resource); 260141cc406Sopenharmony_ci if (query_user == 1) 261141cc406Sopenharmony_ci fprintf (stderr, "Authentication required for resource %*.*s. " 262141cc406Sopenharmony_ci "Enter username: ", len, len, resource); 263141cc406Sopenharmony_ci } 264141cc406Sopenharmony_ci else 265141cc406Sopenharmony_ci { 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci if (accept_only_md5_auth != 0) 268141cc406Sopenharmony_ci { 269141cc406Sopenharmony_ci fprintf (stderr, "ERROR: backend requested plain-text password\n"); 270141cc406Sopenharmony_ci return; 271141cc406Sopenharmony_ci } 272141cc406Sopenharmony_ci else 273141cc406Sopenharmony_ci { 274141cc406Sopenharmony_ci fprintf (stderr, 275141cc406Sopenharmony_ci "WARNING: backend requested plain-text password\n"); 276141cc406Sopenharmony_ci query_user = 1; 277141cc406Sopenharmony_ci } 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci if (query_user == 1) 280141cc406Sopenharmony_ci fprintf (stderr, 281141cc406Sopenharmony_ci "Authentication required for resource %s. Enter username: ", 282141cc406Sopenharmony_ci resource); 283141cc406Sopenharmony_ci } 284141cc406Sopenharmony_ci 285141cc406Sopenharmony_ci if (query_user == 1) 286141cc406Sopenharmony_ci uname = fgets (username, SANE_MAX_USERNAME_LEN, stdin); 287141cc406Sopenharmony_ci 288141cc406Sopenharmony_ci if (uname != NULL && (strlen (username)) && (username[strlen (username) - 1] == '\n')) 289141cc406Sopenharmony_ci username[strlen (username) - 1] = 0; 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci if (query_user == 1) 292141cc406Sopenharmony_ci { 293141cc406Sopenharmony_ci#ifdef HAVE_GETPASS 294141cc406Sopenharmony_ci strcpy (password, (wipe = getpass ("Enter password: "))); 295141cc406Sopenharmony_ci memset (wipe, 0, strlen (password)); 296141cc406Sopenharmony_ci#else 297141cc406Sopenharmony_ci printf("OS has no getpass(). User Queries will not work\n"); 298141cc406Sopenharmony_ci#endif 299141cc406Sopenharmony_ci } 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci if (md5mode) 302141cc406Sopenharmony_ci { 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci sprintf (tmp, "%.128s%.*s", (strstr (resource, "$MD5$")) + 5, 305141cc406Sopenharmony_ci SANE_MAX_PASSWORD_LEN - 1, password); 306141cc406Sopenharmony_ci 307141cc406Sopenharmony_ci md5_buffer (tmp, strlen (tmp), md5digest); 308141cc406Sopenharmony_ci 309141cc406Sopenharmony_ci memset (password, 0, SANE_MAX_PASSWORD_LEN); 310141cc406Sopenharmony_ci 311141cc406Sopenharmony_ci sprintf (password, "$MD5$%02x%02x%02x%02x%02x%02x%02x%02x" 312141cc406Sopenharmony_ci "%02x%02x%02x%02x%02x%02x%02x%02x", 313141cc406Sopenharmony_ci md5digest[0], md5digest[1], 314141cc406Sopenharmony_ci md5digest[2], md5digest[3], 315141cc406Sopenharmony_ci md5digest[4], md5digest[5], 316141cc406Sopenharmony_ci md5digest[6], md5digest[7], 317141cc406Sopenharmony_ci md5digest[8], md5digest[9], 318141cc406Sopenharmony_ci md5digest[10], md5digest[11], 319141cc406Sopenharmony_ci md5digest[12], md5digest[13], md5digest[14], md5digest[15]); 320141cc406Sopenharmony_ci } 321141cc406Sopenharmony_ci} 322141cc406Sopenharmony_ci 323141cc406Sopenharmony_cistatic void 324141cc406Sopenharmony_cisighandler (int signum) 325141cc406Sopenharmony_ci{ 326141cc406Sopenharmony_ci static SANE_Bool first_time = SANE_TRUE; 327141cc406Sopenharmony_ci 328141cc406Sopenharmony_ci if (device) 329141cc406Sopenharmony_ci { 330141cc406Sopenharmony_ci fprintf (stderr, "%s: received signal %d\n", prog_name, signum); 331141cc406Sopenharmony_ci if (first_time) 332141cc406Sopenharmony_ci { 333141cc406Sopenharmony_ci first_time = SANE_FALSE; 334141cc406Sopenharmony_ci fprintf (stderr, "%s: trying to stop scanner\n", prog_name); 335141cc406Sopenharmony_ci sane_cancel (device); 336141cc406Sopenharmony_ci } 337141cc406Sopenharmony_ci else 338141cc406Sopenharmony_ci { 339141cc406Sopenharmony_ci fprintf (stderr, "%s: aborting\n", prog_name); 340141cc406Sopenharmony_ci _exit (0); 341141cc406Sopenharmony_ci } 342141cc406Sopenharmony_ci } 343141cc406Sopenharmony_ci} 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_cistatic void 346141cc406Sopenharmony_ciprint_unit (SANE_Unit unit) 347141cc406Sopenharmony_ci{ 348141cc406Sopenharmony_ci switch (unit) 349141cc406Sopenharmony_ci { 350141cc406Sopenharmony_ci case SANE_UNIT_NONE: 351141cc406Sopenharmony_ci break; 352141cc406Sopenharmony_ci case SANE_UNIT_PIXEL: 353141cc406Sopenharmony_ci fputs ("pel", stdout); 354141cc406Sopenharmony_ci break; 355141cc406Sopenharmony_ci case SANE_UNIT_BIT: 356141cc406Sopenharmony_ci fputs ("bit", stdout); 357141cc406Sopenharmony_ci break; 358141cc406Sopenharmony_ci case SANE_UNIT_MM: 359141cc406Sopenharmony_ci fputs ("mm", stdout); 360141cc406Sopenharmony_ci break; 361141cc406Sopenharmony_ci case SANE_UNIT_DPI: 362141cc406Sopenharmony_ci fputs ("dpi", stdout); 363141cc406Sopenharmony_ci break; 364141cc406Sopenharmony_ci case SANE_UNIT_PERCENT: 365141cc406Sopenharmony_ci fputc ('%', stdout); 366141cc406Sopenharmony_ci break; 367141cc406Sopenharmony_ci case SANE_UNIT_MICROSECOND: 368141cc406Sopenharmony_ci fputs ("us", stdout); 369141cc406Sopenharmony_ci break; 370141cc406Sopenharmony_ci } 371141cc406Sopenharmony_ci} 372141cc406Sopenharmony_ci 373141cc406Sopenharmony_cistatic void 374141cc406Sopenharmony_ciprint_option (SANE_Device * device, int opt_num, const SANE_Option_Descriptor *opt) 375141cc406Sopenharmony_ci{ 376141cc406Sopenharmony_ci const char *str, *last_break, *start; 377141cc406Sopenharmony_ci SANE_Bool not_first = SANE_FALSE; 378141cc406Sopenharmony_ci int i, column; 379141cc406Sopenharmony_ci 380141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_GROUP){ 381141cc406Sopenharmony_ci printf (" %s:\n", opt->title); 382141cc406Sopenharmony_ci return; 383141cc406Sopenharmony_ci } 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci /* if both of these are set, option is invalid */ 386141cc406Sopenharmony_ci if((opt->cap & SANE_CAP_SOFT_SELECT) && (opt->cap & SANE_CAP_HARD_SELECT)){ 387141cc406Sopenharmony_ci fprintf (stderr, "%s: invalid option caps, SS+HS\n", prog_name); 388141cc406Sopenharmony_ci return; 389141cc406Sopenharmony_ci } 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_ci /* invalid to select but not detect */ 392141cc406Sopenharmony_ci if((opt->cap & SANE_CAP_SOFT_SELECT) && !(opt->cap & SANE_CAP_SOFT_DETECT)){ 393141cc406Sopenharmony_ci fprintf (stderr, "%s: invalid option caps, SS!SD\n", prog_name); 394141cc406Sopenharmony_ci return; 395141cc406Sopenharmony_ci } 396141cc406Sopenharmony_ci /* standard allows this, though it makes little sense 397141cc406Sopenharmony_ci if(opt->cap & SANE_CAP_HARD_SELECT && !(opt->cap & SANE_CAP_SOFT_DETECT)){ 398141cc406Sopenharmony_ci fprintf (stderr, "%s: invalid option caps, HS!SD\n", prog_name); 399141cc406Sopenharmony_ci return; 400141cc406Sopenharmony_ci }*/ 401141cc406Sopenharmony_ci 402141cc406Sopenharmony_ci /* if one of these three is not set, option is useless, skip it */ 403141cc406Sopenharmony_ci if(!(opt->cap & 404141cc406Sopenharmony_ci (SANE_CAP_SOFT_SELECT | SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT) 405141cc406Sopenharmony_ci )){ 406141cc406Sopenharmony_ci return; 407141cc406Sopenharmony_ci } 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci /* print the option */ 410141cc406Sopenharmony_ci if ( !strcmp (opt->name, "x") 411141cc406Sopenharmony_ci || !strcmp (opt->name, "y") 412141cc406Sopenharmony_ci || !strcmp (opt->name, "t") 413141cc406Sopenharmony_ci || !strcmp (opt->name, "l")) 414141cc406Sopenharmony_ci printf (" -%s", opt->name); 415141cc406Sopenharmony_ci else 416141cc406Sopenharmony_ci printf (" --%s", opt->name); 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci /* print the option choices */ 419141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_BOOL) 420141cc406Sopenharmony_ci { 421141cc406Sopenharmony_ci fputs ("[=(", stdout); 422141cc406Sopenharmony_ci if (opt->cap & SANE_CAP_AUTOMATIC) 423141cc406Sopenharmony_ci fputs ("auto|", stdout); 424141cc406Sopenharmony_ci fputs ("yes|no)]", stdout); 425141cc406Sopenharmony_ci } 426141cc406Sopenharmony_ci else if (opt->type != SANE_TYPE_BUTTON) 427141cc406Sopenharmony_ci { 428141cc406Sopenharmony_ci fputc (' ', stdout); 429141cc406Sopenharmony_ci if (opt->cap & SANE_CAP_AUTOMATIC) 430141cc406Sopenharmony_ci { 431141cc406Sopenharmony_ci fputs ("auto|", stdout); 432141cc406Sopenharmony_ci not_first = SANE_TRUE; 433141cc406Sopenharmony_ci } 434141cc406Sopenharmony_ci switch (opt->constraint_type) 435141cc406Sopenharmony_ci { 436141cc406Sopenharmony_ci case SANE_CONSTRAINT_NONE: 437141cc406Sopenharmony_ci switch (opt->type) 438141cc406Sopenharmony_ci { 439141cc406Sopenharmony_ci case SANE_TYPE_INT: 440141cc406Sopenharmony_ci fputs ("<int>", stdout); 441141cc406Sopenharmony_ci break; 442141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 443141cc406Sopenharmony_ci fputs ("<float>", stdout); 444141cc406Sopenharmony_ci break; 445141cc406Sopenharmony_ci case SANE_TYPE_STRING: 446141cc406Sopenharmony_ci fputs ("<string>", stdout); 447141cc406Sopenharmony_ci break; 448141cc406Sopenharmony_ci default: 449141cc406Sopenharmony_ci break; 450141cc406Sopenharmony_ci } 451141cc406Sopenharmony_ci if (opt->type != SANE_TYPE_STRING 452141cc406Sopenharmony_ci && opt->size > (SANE_Int) sizeof (SANE_Word)) 453141cc406Sopenharmony_ci fputs (",...", stdout); 454141cc406Sopenharmony_ci break; 455141cc406Sopenharmony_ci 456141cc406Sopenharmony_ci case SANE_CONSTRAINT_RANGE: 457141cc406Sopenharmony_ci // Check for no range - some buggy backends can miss this out. 458141cc406Sopenharmony_ci if (!opt->constraint.range) 459141cc406Sopenharmony_ci { 460141cc406Sopenharmony_ci fputs ("{no_range}", stdout); 461141cc406Sopenharmony_ci } 462141cc406Sopenharmony_ci else 463141cc406Sopenharmony_ci { 464141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_INT) 465141cc406Sopenharmony_ci { 466141cc406Sopenharmony_ci if (!strcmp (opt->name, "x")) 467141cc406Sopenharmony_ci { 468141cc406Sopenharmony_ci printf ("%d..%d", opt->constraint.range->min, 469141cc406Sopenharmony_ci opt->constraint.range->max - tl_x); 470141cc406Sopenharmony_ci } 471141cc406Sopenharmony_ci else if (!strcmp (opt->name, "y")) 472141cc406Sopenharmony_ci { 473141cc406Sopenharmony_ci printf ("%d..%d", opt->constraint.range->min, 474141cc406Sopenharmony_ci opt->constraint.range->max - tl_y); 475141cc406Sopenharmony_ci } 476141cc406Sopenharmony_ci else 477141cc406Sopenharmony_ci { 478141cc406Sopenharmony_ci printf ("%d..%d", opt->constraint.range->min, 479141cc406Sopenharmony_ci opt->constraint.range->max); 480141cc406Sopenharmony_ci } 481141cc406Sopenharmony_ci print_unit (opt->unit); 482141cc406Sopenharmony_ci if (opt->size > (SANE_Int) sizeof(SANE_Word)) 483141cc406Sopenharmony_ci fputs (",...", stdout); 484141cc406Sopenharmony_ci if (opt->constraint.range->quant) 485141cc406Sopenharmony_ci printf (" (in steps of %d)", opt->constraint.range->quant); 486141cc406Sopenharmony_ci } 487141cc406Sopenharmony_ci else 488141cc406Sopenharmony_ci { 489141cc406Sopenharmony_ci if (!strcmp (opt->name, "x")) 490141cc406Sopenharmony_ci { 491141cc406Sopenharmony_ci printf ("%g..%g", SANE_UNFIX(opt->constraint.range->min), 492141cc406Sopenharmony_ci SANE_UNFIX(opt->constraint.range->max - tl_x)); 493141cc406Sopenharmony_ci } 494141cc406Sopenharmony_ci else if (!strcmp (opt->name, "y")) 495141cc406Sopenharmony_ci { 496141cc406Sopenharmony_ci printf ("%g..%g", SANE_UNFIX(opt->constraint.range->min), 497141cc406Sopenharmony_ci SANE_UNFIX(opt->constraint.range->max - tl_y)); 498141cc406Sopenharmony_ci } 499141cc406Sopenharmony_ci else 500141cc406Sopenharmony_ci { 501141cc406Sopenharmony_ci printf ("%g..%g", SANE_UNFIX(opt->constraint.range->min), 502141cc406Sopenharmony_ci SANE_UNFIX(opt->constraint.range->max)); 503141cc406Sopenharmony_ci } 504141cc406Sopenharmony_ci print_unit (opt->unit); 505141cc406Sopenharmony_ci if (opt->size > (SANE_Int) sizeof(SANE_Word)) 506141cc406Sopenharmony_ci fputs (",...", stdout); 507141cc406Sopenharmony_ci if (opt->constraint.range->quant) 508141cc406Sopenharmony_ci printf (" (in steps of %g)", 509141cc406Sopenharmony_ci SANE_UNFIX(opt->constraint.range->quant)); 510141cc406Sopenharmony_ci } 511141cc406Sopenharmony_ci } 512141cc406Sopenharmony_ci break; 513141cc406Sopenharmony_ci 514141cc406Sopenharmony_ci case SANE_CONSTRAINT_WORD_LIST: 515141cc406Sopenharmony_ci // Check no words in list or no list - - some buggy backends can miss this out. 516141cc406Sopenharmony_ci // Note the check on < 1 as SANE_Int is signed. 517141cc406Sopenharmony_ci if (!opt->constraint.word_list || (opt->constraint.word_list[0] < 1)) 518141cc406Sopenharmony_ci { 519141cc406Sopenharmony_ci fputs ("{no_wordlist}", stdout); 520141cc406Sopenharmony_ci } 521141cc406Sopenharmony_ci else 522141cc406Sopenharmony_ci { 523141cc406Sopenharmony_ci for (i = 0; i < opt->constraint.word_list[0]; ++i) 524141cc406Sopenharmony_ci { 525141cc406Sopenharmony_ci if (not_first) 526141cc406Sopenharmony_ci fputc ('|', stdout); 527141cc406Sopenharmony_ci 528141cc406Sopenharmony_ci not_first = SANE_TRUE; 529141cc406Sopenharmony_ci 530141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_INT) 531141cc406Sopenharmony_ci printf ("%d", opt->constraint.word_list[i + 1]); 532141cc406Sopenharmony_ci else 533141cc406Sopenharmony_ci printf ("%g", SANE_UNFIX(opt->constraint.word_list[i + 1])); 534141cc406Sopenharmony_ci } 535141cc406Sopenharmony_ci } 536141cc406Sopenharmony_ci 537141cc406Sopenharmony_ci print_unit (opt->unit); 538141cc406Sopenharmony_ci if (opt->size > (SANE_Int) sizeof (SANE_Word)) 539141cc406Sopenharmony_ci fputs (",...", stdout); 540141cc406Sopenharmony_ci break; 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci case SANE_CONSTRAINT_STRING_LIST: 543141cc406Sopenharmony_ci // Check for missing strings - some buggy backends can miss this out. 544141cc406Sopenharmony_ci if (!opt->constraint.string_list || !opt->constraint.string_list[0]) 545141cc406Sopenharmony_ci { 546141cc406Sopenharmony_ci fputs ("{no_stringlist}", stdout); 547141cc406Sopenharmony_ci } 548141cc406Sopenharmony_ci else 549141cc406Sopenharmony_ci { 550141cc406Sopenharmony_ci for (i = 0; opt->constraint.string_list[i]; ++i) 551141cc406Sopenharmony_ci { 552141cc406Sopenharmony_ci if (i > 0) 553141cc406Sopenharmony_ci fputc ('|', stdout); 554141cc406Sopenharmony_ci 555141cc406Sopenharmony_ci fputs (opt->constraint.string_list[i], stdout); 556141cc406Sopenharmony_ci } 557141cc406Sopenharmony_ci } 558141cc406Sopenharmony_ci break; 559141cc406Sopenharmony_ci } 560141cc406Sopenharmony_ci } 561141cc406Sopenharmony_ci 562141cc406Sopenharmony_ci /* print current option value */ 563141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_STRING || opt->size == sizeof (SANE_Word)) 564141cc406Sopenharmony_ci { 565141cc406Sopenharmony_ci if (SANE_OPTION_IS_ACTIVE (opt->cap)) 566141cc406Sopenharmony_ci { 567141cc406Sopenharmony_ci void *val = alloca (opt->size); 568141cc406Sopenharmony_ci sane_control_option (device, opt_num, SANE_ACTION_GET_VALUE, val, 569141cc406Sopenharmony_ci 0); 570141cc406Sopenharmony_ci fputs (" [", stdout); 571141cc406Sopenharmony_ci switch (opt->type) 572141cc406Sopenharmony_ci { 573141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 574141cc406Sopenharmony_ci fputs (*(SANE_Bool *) val ? "yes" : "no", stdout); 575141cc406Sopenharmony_ci break; 576141cc406Sopenharmony_ci 577141cc406Sopenharmony_ci case SANE_TYPE_INT: 578141cc406Sopenharmony_ci if (strcmp (opt->name, "l") == 0) 579141cc406Sopenharmony_ci { 580141cc406Sopenharmony_ci tl_x = (*(SANE_Fixed *) val); 581141cc406Sopenharmony_ci printf ("%d", tl_x); 582141cc406Sopenharmony_ci } 583141cc406Sopenharmony_ci else if (strcmp (opt->name, "t") == 0) 584141cc406Sopenharmony_ci { 585141cc406Sopenharmony_ci tl_y = (*(SANE_Fixed *) val); 586141cc406Sopenharmony_ci printf ("%d", tl_y); 587141cc406Sopenharmony_ci } 588141cc406Sopenharmony_ci else if (strcmp (opt->name, "x") == 0) 589141cc406Sopenharmony_ci { 590141cc406Sopenharmony_ci br_x = (*(SANE_Fixed *) val); 591141cc406Sopenharmony_ci printf ("%d", br_x - tl_x); 592141cc406Sopenharmony_ci } 593141cc406Sopenharmony_ci else if (strcmp (opt->name, "y") == 0) 594141cc406Sopenharmony_ci { 595141cc406Sopenharmony_ci br_y = (*(SANE_Fixed *) val); 596141cc406Sopenharmony_ci printf ("%d", br_y - tl_y); 597141cc406Sopenharmony_ci } 598141cc406Sopenharmony_ci else 599141cc406Sopenharmony_ci printf ("%d", *(SANE_Int *) val); 600141cc406Sopenharmony_ci break; 601141cc406Sopenharmony_ci 602141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 603141cc406Sopenharmony_ci 604141cc406Sopenharmony_ci if (strcmp (opt->name, "l") == 0) 605141cc406Sopenharmony_ci { 606141cc406Sopenharmony_ci tl_x = (*(SANE_Fixed *) val); 607141cc406Sopenharmony_ci printf ("%g", SANE_UNFIX (tl_x)); 608141cc406Sopenharmony_ci } 609141cc406Sopenharmony_ci else if (strcmp (opt->name, "t") == 0) 610141cc406Sopenharmony_ci { 611141cc406Sopenharmony_ci tl_y = (*(SANE_Fixed *) val); 612141cc406Sopenharmony_ci printf ("%g", SANE_UNFIX (tl_y)); 613141cc406Sopenharmony_ci } 614141cc406Sopenharmony_ci else if (strcmp (opt->name, "x") == 0) 615141cc406Sopenharmony_ci { 616141cc406Sopenharmony_ci br_x = (*(SANE_Fixed *) val); 617141cc406Sopenharmony_ci printf ("%g", SANE_UNFIX (br_x - tl_x)); 618141cc406Sopenharmony_ci } 619141cc406Sopenharmony_ci else if (strcmp (opt->name, "y") == 0) 620141cc406Sopenharmony_ci { 621141cc406Sopenharmony_ci br_y = (*(SANE_Fixed *) val); 622141cc406Sopenharmony_ci printf ("%g", SANE_UNFIX (br_y - tl_y)); 623141cc406Sopenharmony_ci } 624141cc406Sopenharmony_ci else 625141cc406Sopenharmony_ci printf ("%g", SANE_UNFIX (*(SANE_Fixed *) val)); 626141cc406Sopenharmony_ci 627141cc406Sopenharmony_ci break; 628141cc406Sopenharmony_ci 629141cc406Sopenharmony_ci case SANE_TYPE_STRING: 630141cc406Sopenharmony_ci fputs ((char *) val, stdout); 631141cc406Sopenharmony_ci break; 632141cc406Sopenharmony_ci 633141cc406Sopenharmony_ci default: 634141cc406Sopenharmony_ci break; 635141cc406Sopenharmony_ci } 636141cc406Sopenharmony_ci fputc (']', stdout); 637141cc406Sopenharmony_ci } 638141cc406Sopenharmony_ci } 639141cc406Sopenharmony_ci 640141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (opt->cap)) 641141cc406Sopenharmony_ci fputs (" [inactive]", stdout); 642141cc406Sopenharmony_ci 643141cc406Sopenharmony_ci else if(opt->cap & SANE_CAP_HARD_SELECT) 644141cc406Sopenharmony_ci fputs (" [hardware]", stdout); 645141cc406Sopenharmony_ci 646141cc406Sopenharmony_ci else if(!(opt->cap & SANE_CAP_SOFT_SELECT) && (opt->cap & SANE_CAP_SOFT_DETECT)) 647141cc406Sopenharmony_ci fputs (" [read-only]", stdout); 648141cc406Sopenharmony_ci 649141cc406Sopenharmony_ci else if (opt->cap & SANE_CAP_ADVANCED) 650141cc406Sopenharmony_ci fputs (" [advanced]", stdout); 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci fputs ("\n ", stdout); 653141cc406Sopenharmony_ci 654141cc406Sopenharmony_ci column = 8; 655141cc406Sopenharmony_ci last_break = 0; 656141cc406Sopenharmony_ci start = opt->desc; 657141cc406Sopenharmony_ci for (str = opt->desc; *str; ++str) 658141cc406Sopenharmony_ci { 659141cc406Sopenharmony_ci ++column; 660141cc406Sopenharmony_ci if (*str == ' ') 661141cc406Sopenharmony_ci last_break = str; 662141cc406Sopenharmony_ci else if (*str == '\n'){ 663141cc406Sopenharmony_ci column=80; 664141cc406Sopenharmony_ci last_break = str; 665141cc406Sopenharmony_ci } 666141cc406Sopenharmony_ci if (column >= 79 && last_break) 667141cc406Sopenharmony_ci { 668141cc406Sopenharmony_ci while (start < last_break) 669141cc406Sopenharmony_ci fputc (*start++, stdout); 670141cc406Sopenharmony_ci start = last_break + 1; /* skip blank */ 671141cc406Sopenharmony_ci fputs ("\n ", stdout); 672141cc406Sopenharmony_ci column = 8 + (str - start); 673141cc406Sopenharmony_ci } 674141cc406Sopenharmony_ci } 675141cc406Sopenharmony_ci while (*start) 676141cc406Sopenharmony_ci fputc (*start++, stdout); 677141cc406Sopenharmony_ci fputc ('\n', stdout); 678141cc406Sopenharmony_ci} 679141cc406Sopenharmony_ci 680141cc406Sopenharmony_ci/* A scalar has the following syntax: 681141cc406Sopenharmony_ci 682141cc406Sopenharmony_ci V [ U ] 683141cc406Sopenharmony_ci 684141cc406Sopenharmony_ci V is the value of the scalar. It is either an integer or a 685141cc406Sopenharmony_ci floating point number, depending on the option type. 686141cc406Sopenharmony_ci 687141cc406Sopenharmony_ci U is an optional unit. If not specified, the default unit is used. 688141cc406Sopenharmony_ci The following table lists which units are supported depending on 689141cc406Sopenharmony_ci what the option's default unit is: 690141cc406Sopenharmony_ci 691141cc406Sopenharmony_ci Option's unit: Allowed units: 692141cc406Sopenharmony_ci 693141cc406Sopenharmony_ci SANE_UNIT_NONE: 694141cc406Sopenharmony_ci SANE_UNIT_PIXEL: pel 695141cc406Sopenharmony_ci SANE_UNIT_BIT: b (bit), B (byte) 696141cc406Sopenharmony_ci SANE_UNIT_MM: mm (millimeter), cm (centimeter), in or " (inches), 697141cc406Sopenharmony_ci SANE_UNIT_DPI: dpi 698141cc406Sopenharmony_ci SANE_UNIT_PERCENT: % 699141cc406Sopenharmony_ci SANE_UNIT_PERCENT: us 700141cc406Sopenharmony_ci */ 701141cc406Sopenharmony_cistatic const char * 702141cc406Sopenharmony_ciparse_scalar (const SANE_Option_Descriptor * opt, const char *str, 703141cc406Sopenharmony_ci SANE_Word * value) 704141cc406Sopenharmony_ci{ 705141cc406Sopenharmony_ci char *end; 706141cc406Sopenharmony_ci double v; 707141cc406Sopenharmony_ci 708141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_FIXED) 709141cc406Sopenharmony_ci v = strtod (str, &end) * (1 << SANE_FIXED_SCALE_SHIFT); 710141cc406Sopenharmony_ci else 711141cc406Sopenharmony_ci v = strtol (str, &end, 10); 712141cc406Sopenharmony_ci 713141cc406Sopenharmony_ci if (str == end) 714141cc406Sopenharmony_ci { 715141cc406Sopenharmony_ci fprintf (stderr, 716141cc406Sopenharmony_ci "%s: option --%s: bad option value (rest of option: %s)\n", 717141cc406Sopenharmony_ci prog_name, opt->name, str); 718141cc406Sopenharmony_ci scanimage_exit (1); 719141cc406Sopenharmony_ci } 720141cc406Sopenharmony_ci str = end; 721141cc406Sopenharmony_ci 722141cc406Sopenharmony_ci switch (opt->unit) 723141cc406Sopenharmony_ci { 724141cc406Sopenharmony_ci case SANE_UNIT_NONE: 725141cc406Sopenharmony_ci case SANE_UNIT_PIXEL: 726141cc406Sopenharmony_ci break; 727141cc406Sopenharmony_ci 728141cc406Sopenharmony_ci case SANE_UNIT_BIT: 729141cc406Sopenharmony_ci if (*str == 'b' || *str == 'B') 730141cc406Sopenharmony_ci { 731141cc406Sopenharmony_ci if (*str++ == 'B') 732141cc406Sopenharmony_ci v *= 8; 733141cc406Sopenharmony_ci } 734141cc406Sopenharmony_ci break; 735141cc406Sopenharmony_ci 736141cc406Sopenharmony_ci case SANE_UNIT_MM: 737141cc406Sopenharmony_ci if (str[0] == '\0') 738141cc406Sopenharmony_ci v *= 1.0; /* default to mm */ 739141cc406Sopenharmony_ci else if (strcmp (str, "mm") == 0) 740141cc406Sopenharmony_ci str += sizeof ("mm") - 1; 741141cc406Sopenharmony_ci else if (strcmp (str, "cm") == 0) 742141cc406Sopenharmony_ci { 743141cc406Sopenharmony_ci str += sizeof ("cm") - 1; 744141cc406Sopenharmony_ci v *= 10.0; 745141cc406Sopenharmony_ci } 746141cc406Sopenharmony_ci else if (strcmp (str, "in") == 0 || *str == '"') 747141cc406Sopenharmony_ci { 748141cc406Sopenharmony_ci if (*str++ != '"') 749141cc406Sopenharmony_ci ++str; 750141cc406Sopenharmony_ci v *= 25.4; /* 25.4 mm/inch */ 751141cc406Sopenharmony_ci } 752141cc406Sopenharmony_ci else 753141cc406Sopenharmony_ci { 754141cc406Sopenharmony_ci fprintf (stderr, 755141cc406Sopenharmony_ci "%s: option --%s: illegal unit (rest of option: %s)\n", 756141cc406Sopenharmony_ci prog_name, opt->name, str); 757141cc406Sopenharmony_ci return 0; 758141cc406Sopenharmony_ci } 759141cc406Sopenharmony_ci break; 760141cc406Sopenharmony_ci 761141cc406Sopenharmony_ci case SANE_UNIT_DPI: 762141cc406Sopenharmony_ci if (strcmp (str, "dpi") == 0) 763141cc406Sopenharmony_ci str += sizeof ("dpi") - 1; 764141cc406Sopenharmony_ci break; 765141cc406Sopenharmony_ci 766141cc406Sopenharmony_ci case SANE_UNIT_PERCENT: 767141cc406Sopenharmony_ci if (*str == '%') 768141cc406Sopenharmony_ci ++str; 769141cc406Sopenharmony_ci break; 770141cc406Sopenharmony_ci 771141cc406Sopenharmony_ci case SANE_UNIT_MICROSECOND: 772141cc406Sopenharmony_ci if (strcmp (str, "us") == 0) 773141cc406Sopenharmony_ci str += sizeof ("us") - 1; 774141cc406Sopenharmony_ci break; 775141cc406Sopenharmony_ci } 776141cc406Sopenharmony_ci 777141cc406Sopenharmony_ci if(v < 0){ 778141cc406Sopenharmony_ci *value = v - 0.5; 779141cc406Sopenharmony_ci } 780141cc406Sopenharmony_ci else{ 781141cc406Sopenharmony_ci *value = v + 0.5; 782141cc406Sopenharmony_ci } 783141cc406Sopenharmony_ci 784141cc406Sopenharmony_ci return str; 785141cc406Sopenharmony_ci} 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_ci/* A vector has the following syntax: 788141cc406Sopenharmony_ci 789141cc406Sopenharmony_ci [ '[' I ']' ] S { [','|'-'] [ '[' I ']' S } 790141cc406Sopenharmony_ci 791141cc406Sopenharmony_ci The number in brackets (I), if present, determines the index of the 792141cc406Sopenharmony_ci vector element to be set next. If I is not present, the value of 793141cc406Sopenharmony_ci last index used plus 1 is used. The first index value used is 0 794141cc406Sopenharmony_ci unless I is present. 795141cc406Sopenharmony_ci 796141cc406Sopenharmony_ci S is a scalar value as defined by parse_scalar(). 797141cc406Sopenharmony_ci 798141cc406Sopenharmony_ci If two consecutive value specs are separated by a comma (,) their 799141cc406Sopenharmony_ci values are set independently. If they are separated by a dash (-), 800141cc406Sopenharmony_ci they define the endpoints of a line and all vector values between 801141cc406Sopenharmony_ci the two endpoints are set according to the value of the 802141cc406Sopenharmony_ci interpolated line. For example, [0]15-[255]15 defines a vector of 803141cc406Sopenharmony_ci 256 elements whose value is 15. Similarly, [0]0-[255]255 defines a 804141cc406Sopenharmony_ci vector of 256 elements whose value starts at 0 and increases to 805141cc406Sopenharmony_ci 255. */ 806141cc406Sopenharmony_cistatic void 807141cc406Sopenharmony_ciparse_vector (const SANE_Option_Descriptor * opt, const char *str, 808141cc406Sopenharmony_ci SANE_Word * vector, size_t vector_length) 809141cc406Sopenharmony_ci{ 810141cc406Sopenharmony_ci SANE_Word value, prev_value = 0; 811141cc406Sopenharmony_ci int index = -1, prev_index = 0; 812141cc406Sopenharmony_ci char *end, separator = '\0'; 813141cc406Sopenharmony_ci 814141cc406Sopenharmony_ci /* initialize vector to all zeroes: */ 815141cc406Sopenharmony_ci memset (vector, 0, vector_length * sizeof (SANE_Word)); 816141cc406Sopenharmony_ci 817141cc406Sopenharmony_ci do 818141cc406Sopenharmony_ci { 819141cc406Sopenharmony_ci if (*str == '[') 820141cc406Sopenharmony_ci { 821141cc406Sopenharmony_ci /* read index */ 822141cc406Sopenharmony_ci index = strtol (++str, &end, 10); 823141cc406Sopenharmony_ci if (str == end || *end != ']') 824141cc406Sopenharmony_ci { 825141cc406Sopenharmony_ci fprintf (stderr, "%s: option --%s: closing bracket missing " 826141cc406Sopenharmony_ci "(rest of option: %s)\n", prog_name, opt->name, str); 827141cc406Sopenharmony_ci scanimage_exit (1); 828141cc406Sopenharmony_ci } 829141cc406Sopenharmony_ci str = end + 1; 830141cc406Sopenharmony_ci } 831141cc406Sopenharmony_ci else 832141cc406Sopenharmony_ci ++index; 833141cc406Sopenharmony_ci 834141cc406Sopenharmony_ci if (index < 0 || index >= (int) vector_length) 835141cc406Sopenharmony_ci { 836141cc406Sopenharmony_ci fprintf (stderr, 837141cc406Sopenharmony_ci "%s: option --%s: index %d out of range [0..%ld]\n", 838141cc406Sopenharmony_ci prog_name, opt->name, index, (long) vector_length - 1); 839141cc406Sopenharmony_ci scanimage_exit (1); 840141cc406Sopenharmony_ci } 841141cc406Sopenharmony_ci 842141cc406Sopenharmony_ci /* read value */ 843141cc406Sopenharmony_ci str = parse_scalar (opt, str, &value); 844141cc406Sopenharmony_ci if (!str) 845141cc406Sopenharmony_ci scanimage_exit (1); 846141cc406Sopenharmony_ci 847141cc406Sopenharmony_ci if (*str && *str != '-' && *str != ',') 848141cc406Sopenharmony_ci { 849141cc406Sopenharmony_ci fprintf (stderr, 850141cc406Sopenharmony_ci "%s: option --%s: illegal separator (rest of option: %s)\n", 851141cc406Sopenharmony_ci prog_name, opt->name, str); 852141cc406Sopenharmony_ci scanimage_exit (1); 853141cc406Sopenharmony_ci } 854141cc406Sopenharmony_ci 855141cc406Sopenharmony_ci /* store value: */ 856141cc406Sopenharmony_ci vector[index] = value; 857141cc406Sopenharmony_ci if (separator == '-') 858141cc406Sopenharmony_ci { 859141cc406Sopenharmony_ci /* interpolate */ 860141cc406Sopenharmony_ci double v, slope; 861141cc406Sopenharmony_ci int i; 862141cc406Sopenharmony_ci 863141cc406Sopenharmony_ci v = (double) prev_value; 864141cc406Sopenharmony_ci slope = ((double) value - v) / (index - prev_index); 865141cc406Sopenharmony_ci 866141cc406Sopenharmony_ci for (i = prev_index + 1; i < index; ++i) 867141cc406Sopenharmony_ci { 868141cc406Sopenharmony_ci v += slope; 869141cc406Sopenharmony_ci vector[i] = (SANE_Word) v; 870141cc406Sopenharmony_ci } 871141cc406Sopenharmony_ci } 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci prev_index = index; 874141cc406Sopenharmony_ci prev_value = value; 875141cc406Sopenharmony_ci separator = *str++; 876141cc406Sopenharmony_ci } 877141cc406Sopenharmony_ci while (separator == ',' || separator == '-'); 878141cc406Sopenharmony_ci 879141cc406Sopenharmony_ci if (verbose > 2) 880141cc406Sopenharmony_ci { 881141cc406Sopenharmony_ci int i; 882141cc406Sopenharmony_ci 883141cc406Sopenharmony_ci fprintf (stderr, "%s: value for --%s is: ", prog_name, opt->name); 884141cc406Sopenharmony_ci for (i = 0; i < (int) vector_length; ++i) 885141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_FIXED) 886141cc406Sopenharmony_ci fprintf (stderr, "%g ", SANE_UNFIX (vector[i])); 887141cc406Sopenharmony_ci else 888141cc406Sopenharmony_ci fprintf (stderr, "%d ", vector[i]); 889141cc406Sopenharmony_ci fputc ('\n', stderr); 890141cc406Sopenharmony_ci } 891141cc406Sopenharmony_ci} 892141cc406Sopenharmony_ci 893141cc406Sopenharmony_cistatic void 894141cc406Sopenharmony_cifetch_options (SANE_Device * device) 895141cc406Sopenharmony_ci{ 896141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 897141cc406Sopenharmony_ci SANE_Int num_dev_options; 898141cc406Sopenharmony_ci int i, option_count; 899141cc406Sopenharmony_ci SANE_Status status; 900141cc406Sopenharmony_ci 901141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, 0); 902141cc406Sopenharmony_ci if (opt == NULL) 903141cc406Sopenharmony_ci { 904141cc406Sopenharmony_ci fprintf (stderr, "Could not get option descriptor for option 0\n"); 905141cc406Sopenharmony_ci scanimage_exit (1); 906141cc406Sopenharmony_ci } 907141cc406Sopenharmony_ci 908141cc406Sopenharmony_ci status = sane_control_option (device, 0, SANE_ACTION_GET_VALUE, 909141cc406Sopenharmony_ci &num_dev_options, 0); 910141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 911141cc406Sopenharmony_ci { 912141cc406Sopenharmony_ci fprintf (stderr, "Could not get value for option 0: %s\n", 913141cc406Sopenharmony_ci sane_strstatus (status)); 914141cc406Sopenharmony_ci scanimage_exit (1); 915141cc406Sopenharmony_ci } 916141cc406Sopenharmony_ci 917141cc406Sopenharmony_ci /* build the full table of long options */ 918141cc406Sopenharmony_ci option_count = 0; 919141cc406Sopenharmony_ci for (i = 1; i < num_dev_options; ++i) 920141cc406Sopenharmony_ci { 921141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, i); 922141cc406Sopenharmony_ci if (opt == NULL) 923141cc406Sopenharmony_ci { 924141cc406Sopenharmony_ci fprintf (stderr, "Could not get option descriptor for option %d\n",i); 925141cc406Sopenharmony_ci scanimage_exit (1); 926141cc406Sopenharmony_ci } 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci /* create command line option only for non-group options */ 929141cc406Sopenharmony_ci /* Also we sometimes see options with no name in rogue backends. */ 930141cc406Sopenharmony_ci if ((opt->type == SANE_TYPE_GROUP) || (opt->name == NULL)) 931141cc406Sopenharmony_ci continue; 932141cc406Sopenharmony_ci 933141cc406Sopenharmony_ci option_number[option_count] = i; 934141cc406Sopenharmony_ci 935141cc406Sopenharmony_ci all_options[option_count].name = (const char *) opt->name; 936141cc406Sopenharmony_ci all_options[option_count].flag = 0; 937141cc406Sopenharmony_ci all_options[option_count].val = 0; 938141cc406Sopenharmony_ci 939141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_BOOL) 940141cc406Sopenharmony_ci all_options[option_count].has_arg = optional_argument; 941141cc406Sopenharmony_ci else if (opt->type == SANE_TYPE_BUTTON) 942141cc406Sopenharmony_ci all_options[option_count].has_arg = no_argument; 943141cc406Sopenharmony_ci else 944141cc406Sopenharmony_ci all_options[option_count].has_arg = required_argument; 945141cc406Sopenharmony_ci 946141cc406Sopenharmony_ci /* Look for scan resolution */ 947141cc406Sopenharmony_ci if ((opt->type == SANE_TYPE_FIXED || opt->type == SANE_TYPE_INT) 948141cc406Sopenharmony_ci && opt->size == sizeof (SANE_Int) 949141cc406Sopenharmony_ci && (opt->unit == SANE_UNIT_DPI) 950141cc406Sopenharmony_ci && (strcmp (opt->name, SANE_NAME_SCAN_RESOLUTION) == 0)) 951141cc406Sopenharmony_ci resolution_optind = i; 952141cc406Sopenharmony_ci 953141cc406Sopenharmony_ci /* Keep track of top-left corner options (if they exist at 954141cc406Sopenharmony_ci all) and replace the bottom-right corner options by a 955141cc406Sopenharmony_ci width/height option (if they exist at all). */ 956141cc406Sopenharmony_ci if ((opt->type == SANE_TYPE_FIXED || opt->type == SANE_TYPE_INT) 957141cc406Sopenharmony_ci && opt->size == sizeof (SANE_Int) 958141cc406Sopenharmony_ci && (opt->unit == SANE_UNIT_MM || opt->unit == SANE_UNIT_PIXEL)) 959141cc406Sopenharmony_ci { 960141cc406Sopenharmony_ci if (strcmp (opt->name, SANE_NAME_SCAN_BR_X) == 0) 961141cc406Sopenharmony_ci { 962141cc406Sopenharmony_ci window[0] = i; 963141cc406Sopenharmony_ci all_options[option_count].name = "width"; 964141cc406Sopenharmony_ci all_options[option_count].val = 'x'; 965141cc406Sopenharmony_ci window_option[0] = *opt; 966141cc406Sopenharmony_ci window_option[0].title = "Scan width"; 967141cc406Sopenharmony_ci window_option[0].desc = "Width of scan-area."; 968141cc406Sopenharmony_ci window_option[0].name = "x"; 969141cc406Sopenharmony_ci } 970141cc406Sopenharmony_ci else if (strcmp (opt->name, SANE_NAME_SCAN_BR_Y) == 0) 971141cc406Sopenharmony_ci { 972141cc406Sopenharmony_ci window[1] = i; 973141cc406Sopenharmony_ci all_options[option_count].name = "height"; 974141cc406Sopenharmony_ci all_options[option_count].val = 'y'; 975141cc406Sopenharmony_ci window_option[1] = *opt; 976141cc406Sopenharmony_ci window_option[1].title = "Scan height"; 977141cc406Sopenharmony_ci window_option[1].desc = "Height of scan-area."; 978141cc406Sopenharmony_ci window_option[1].name = "y"; 979141cc406Sopenharmony_ci } 980141cc406Sopenharmony_ci else if (strcmp (opt->name, SANE_NAME_SCAN_TL_X) == 0) 981141cc406Sopenharmony_ci { 982141cc406Sopenharmony_ci window[2] = i; 983141cc406Sopenharmony_ci all_options[option_count].val = 'l'; 984141cc406Sopenharmony_ci window_option[2] = *opt; 985141cc406Sopenharmony_ci window_option[2].name = "l"; 986141cc406Sopenharmony_ci } 987141cc406Sopenharmony_ci else if (strcmp (opt->name, SANE_NAME_SCAN_TL_Y) == 0) 988141cc406Sopenharmony_ci { 989141cc406Sopenharmony_ci window[3] = i; 990141cc406Sopenharmony_ci all_options[option_count].val = 't'; 991141cc406Sopenharmony_ci window_option[3] = *opt; 992141cc406Sopenharmony_ci window_option[3].name = "t"; 993141cc406Sopenharmony_ci } 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci ++option_count; 996141cc406Sopenharmony_ci } 997141cc406Sopenharmony_ci memcpy (all_options + option_count, basic_options, sizeof (basic_options)); 998141cc406Sopenharmony_ci option_count += NELEMS (basic_options); 999141cc406Sopenharmony_ci memset (all_options + option_count, 0, sizeof (all_options[0])); 1000141cc406Sopenharmony_ci 1001141cc406Sopenharmony_ci /* Initialize width & height options based on backend default 1002141cc406Sopenharmony_ci values for top-left x/y and bottom-right x/y: */ 1003141cc406Sopenharmony_ci for (i = 0; i < 2; ++i) 1004141cc406Sopenharmony_ci { 1005141cc406Sopenharmony_ci if (window[i] && !window_val_user[i]) 1006141cc406Sopenharmony_ci { 1007141cc406Sopenharmony_ci sane_control_option (device, window[i], 1008141cc406Sopenharmony_ci SANE_ACTION_GET_VALUE, &window_val[i], 0); 1009141cc406Sopenharmony_ci if (window[i + 2]){ 1010141cc406Sopenharmony_ci SANE_Word pos; 1011141cc406Sopenharmony_ci sane_control_option (device, window[i + 2], 1012141cc406Sopenharmony_ci SANE_ACTION_GET_VALUE, &pos, 0); 1013141cc406Sopenharmony_ci window_val[i] -= pos; 1014141cc406Sopenharmony_ci } 1015141cc406Sopenharmony_ci } 1016141cc406Sopenharmony_ci } 1017141cc406Sopenharmony_ci} 1018141cc406Sopenharmony_ci 1019141cc406Sopenharmony_cistatic void 1020141cc406Sopenharmony_ciset_option (SANE_Handle device, int optnum, void *valuep) 1021141cc406Sopenharmony_ci{ 1022141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 1023141cc406Sopenharmony_ci SANE_Status status; 1024141cc406Sopenharmony_ci SANE_Word orig = 0; 1025141cc406Sopenharmony_ci SANE_Int info = 0; 1026141cc406Sopenharmony_ci 1027141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, optnum); 1028141cc406Sopenharmony_ci if (!opt) 1029141cc406Sopenharmony_ci { 1030141cc406Sopenharmony_ci if (verbose > 0) 1031141cc406Sopenharmony_ci fprintf (stderr, "%s: ignored request to set invalid option %d\n", 1032141cc406Sopenharmony_ci prog_name, optnum); 1033141cc406Sopenharmony_ci return; 1034141cc406Sopenharmony_ci } 1035141cc406Sopenharmony_ci 1036141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (opt->cap)) 1037141cc406Sopenharmony_ci { 1038141cc406Sopenharmony_ci if (verbose > 0) 1039141cc406Sopenharmony_ci fprintf (stderr, "%s: ignored request to set inactive option %s\n", 1040141cc406Sopenharmony_ci prog_name, opt->name); 1041141cc406Sopenharmony_ci return; 1042141cc406Sopenharmony_ci } 1043141cc406Sopenharmony_ci 1044141cc406Sopenharmony_ci if (opt->size == sizeof (SANE_Word) && opt->type != SANE_TYPE_STRING) 1045141cc406Sopenharmony_ci orig = *(SANE_Word *) valuep; 1046141cc406Sopenharmony_ci 1047141cc406Sopenharmony_ci status = sane_control_option (device, optnum, SANE_ACTION_SET_VALUE, 1048141cc406Sopenharmony_ci valuep, &info); 1049141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1050141cc406Sopenharmony_ci { 1051141cc406Sopenharmony_ci fprintf (stderr, "%s: setting of option --%s failed (%s)\n", 1052141cc406Sopenharmony_ci prog_name, opt->name, sane_strstatus (status)); 1053141cc406Sopenharmony_ci scanimage_exit (1); 1054141cc406Sopenharmony_ci } 1055141cc406Sopenharmony_ci 1056141cc406Sopenharmony_ci if ((info & SANE_INFO_INEXACT) && opt->size == sizeof (SANE_Word)) 1057141cc406Sopenharmony_ci { 1058141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_INT) 1059141cc406Sopenharmony_ci fprintf (stderr, "%s: rounded value of %s from %d to %d\n", 1060141cc406Sopenharmony_ci prog_name, opt->name, orig, *(SANE_Word *) valuep); 1061141cc406Sopenharmony_ci else if (opt->type == SANE_TYPE_FIXED) 1062141cc406Sopenharmony_ci fprintf (stderr, "%s: rounded value of %s from %g to %g\n", 1063141cc406Sopenharmony_ci prog_name, opt->name, 1064141cc406Sopenharmony_ci SANE_UNFIX (orig), SANE_UNFIX (*(SANE_Word *) valuep)); 1065141cc406Sopenharmony_ci } 1066141cc406Sopenharmony_ci 1067141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_OPTIONS) 1068141cc406Sopenharmony_ci fetch_options (device); 1069141cc406Sopenharmony_ci} 1070141cc406Sopenharmony_ci 1071141cc406Sopenharmony_cistatic void 1072141cc406Sopenharmony_ciprocess_backend_option (SANE_Handle device, int optnum, const char *optarg) 1073141cc406Sopenharmony_ci{ 1074141cc406Sopenharmony_ci static SANE_Word *vector = 0; 1075141cc406Sopenharmony_ci static size_t vector_size = 0; 1076141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 1077141cc406Sopenharmony_ci size_t vector_length; 1078141cc406Sopenharmony_ci SANE_Status status; 1079141cc406Sopenharmony_ci SANE_Word value; 1080141cc406Sopenharmony_ci void *valuep; 1081141cc406Sopenharmony_ci 1082141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, optnum); 1083141cc406Sopenharmony_ci 1084141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (opt->cap)) 1085141cc406Sopenharmony_ci { 1086141cc406Sopenharmony_ci fprintf (stderr, "%s: attempted to set readonly option %s\n", 1087141cc406Sopenharmony_ci prog_name, opt->name); 1088141cc406Sopenharmony_ci scanimage_exit (1); 1089141cc406Sopenharmony_ci } 1090141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (opt->cap)) 1091141cc406Sopenharmony_ci { 1092141cc406Sopenharmony_ci fprintf (stderr, "%s: attempted to set inactive option %s\n", 1093141cc406Sopenharmony_ci prog_name, opt->name); 1094141cc406Sopenharmony_ci scanimage_exit (1); 1095141cc406Sopenharmony_ci } 1096141cc406Sopenharmony_ci 1097141cc406Sopenharmony_ci if ((opt->cap & SANE_CAP_AUTOMATIC) && optarg && 1098141cc406Sopenharmony_ci strncasecmp (optarg, "auto", 4) == 0) 1099141cc406Sopenharmony_ci { 1100141cc406Sopenharmony_ci status = sane_control_option (device, optnum, SANE_ACTION_SET_AUTO, 1101141cc406Sopenharmony_ci 0, 0); 1102141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1103141cc406Sopenharmony_ci { 1104141cc406Sopenharmony_ci fprintf (stderr, 1105141cc406Sopenharmony_ci "%s: failed to set option --%s to automatic (%s)\n", 1106141cc406Sopenharmony_ci prog_name, opt->name, sane_strstatus (status)); 1107141cc406Sopenharmony_ci scanimage_exit (1); 1108141cc406Sopenharmony_ci } 1109141cc406Sopenharmony_ci return; 1110141cc406Sopenharmony_ci } 1111141cc406Sopenharmony_ci 1112141cc406Sopenharmony_ci valuep = &value; 1113141cc406Sopenharmony_ci switch (opt->type) 1114141cc406Sopenharmony_ci { 1115141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 1116141cc406Sopenharmony_ci value = 1; /* no argument means option is set */ 1117141cc406Sopenharmony_ci if (optarg) 1118141cc406Sopenharmony_ci { 1119141cc406Sopenharmony_ci if (strncasecmp (optarg, "yes", strlen (optarg)) == 0) 1120141cc406Sopenharmony_ci value = 1; 1121141cc406Sopenharmony_ci else if (strncasecmp (optarg, "no", strlen (optarg)) == 0) 1122141cc406Sopenharmony_ci value = 0; 1123141cc406Sopenharmony_ci else 1124141cc406Sopenharmony_ci { 1125141cc406Sopenharmony_ci fprintf (stderr, "%s: option --%s: bad option value `%s'\n", 1126141cc406Sopenharmony_ci prog_name, opt->name, optarg); 1127141cc406Sopenharmony_ci scanimage_exit (1); 1128141cc406Sopenharmony_ci } 1129141cc406Sopenharmony_ci } 1130141cc406Sopenharmony_ci break; 1131141cc406Sopenharmony_ci 1132141cc406Sopenharmony_ci case SANE_TYPE_INT: 1133141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 1134141cc406Sopenharmony_ci /* ensure vector is long enough: */ 1135141cc406Sopenharmony_ci vector_length = opt->size / sizeof (SANE_Word); 1136141cc406Sopenharmony_ci if (vector_size < vector_length) 1137141cc406Sopenharmony_ci { 1138141cc406Sopenharmony_ci vector_size = vector_length; 1139141cc406Sopenharmony_ci vector = realloc (vector, vector_length * sizeof (SANE_Word)); 1140141cc406Sopenharmony_ci if (!vector) 1141141cc406Sopenharmony_ci { 1142141cc406Sopenharmony_ci fprintf (stderr, "%s: out of memory\n", prog_name); 1143141cc406Sopenharmony_ci scanimage_exit (1); 1144141cc406Sopenharmony_ci } 1145141cc406Sopenharmony_ci } 1146141cc406Sopenharmony_ci parse_vector (opt, optarg, vector, vector_length); 1147141cc406Sopenharmony_ci valuep = vector; 1148141cc406Sopenharmony_ci break; 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci case SANE_TYPE_STRING: 1151141cc406Sopenharmony_ci valuep = malloc (opt->size); 1152141cc406Sopenharmony_ci if (!valuep) 1153141cc406Sopenharmony_ci { 1154141cc406Sopenharmony_ci fprintf (stderr, "%s: out of memory\n", prog_name); 1155141cc406Sopenharmony_ci scanimage_exit (1); 1156141cc406Sopenharmony_ci } 1157141cc406Sopenharmony_ci strncpy (valuep, optarg, opt->size); 1158141cc406Sopenharmony_ci ((char *) valuep)[opt->size - 1] = 0; 1159141cc406Sopenharmony_ci break; 1160141cc406Sopenharmony_ci 1161141cc406Sopenharmony_ci case SANE_TYPE_BUTTON: 1162141cc406Sopenharmony_ci value = 0; /* value doesn't matter */ 1163141cc406Sopenharmony_ci break; 1164141cc406Sopenharmony_ci 1165141cc406Sopenharmony_ci default: 1166141cc406Sopenharmony_ci fprintf (stderr, "%s: duh, got unknown option type %d\n", 1167141cc406Sopenharmony_ci prog_name, opt->type); 1168141cc406Sopenharmony_ci return; 1169141cc406Sopenharmony_ci } 1170141cc406Sopenharmony_ci set_option (device, optnum, valuep); 1171141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_STRING && valuep) 1172141cc406Sopenharmony_ci free(valuep); 1173141cc406Sopenharmony_ci} 1174141cc406Sopenharmony_ci 1175141cc406Sopenharmony_cistatic void 1176141cc406Sopenharmony_ciwrite_pnm_header (SANE_Frame format, int width, int height, int depth, FILE *ofp) 1177141cc406Sopenharmony_ci{ 1178141cc406Sopenharmony_ci /* The netpbm-package does not define raw image data with maxval > 255. */ 1179141cc406Sopenharmony_ci /* But writing maxval 65535 for 16bit data gives at least a chance */ 1180141cc406Sopenharmony_ci /* to read the image. */ 1181141cc406Sopenharmony_ci switch (format) 1182141cc406Sopenharmony_ci { 1183141cc406Sopenharmony_ci case SANE_FRAME_RED: 1184141cc406Sopenharmony_ci case SANE_FRAME_GREEN: 1185141cc406Sopenharmony_ci case SANE_FRAME_BLUE: 1186141cc406Sopenharmony_ci case SANE_FRAME_RGB: 1187141cc406Sopenharmony_ci fprintf (ofp, "P6\n# SANE data follows\n%d %d\n%d\n", width, height, 1188141cc406Sopenharmony_ci (depth <= 8) ? 255 : 65535); 1189141cc406Sopenharmony_ci break; 1190141cc406Sopenharmony_ci 1191141cc406Sopenharmony_ci default: 1192141cc406Sopenharmony_ci if (depth == 1) 1193141cc406Sopenharmony_ci fprintf (ofp, "P4\n# SANE data follows\n%d %d\n", width, height); 1194141cc406Sopenharmony_ci else 1195141cc406Sopenharmony_ci fprintf (ofp, "P5\n# SANE data follows\n%d %d\n%d\n", width, height, 1196141cc406Sopenharmony_ci (depth <= 8) ? 255 : 65535); 1197141cc406Sopenharmony_ci break; 1198141cc406Sopenharmony_ci } 1199141cc406Sopenharmony_ci#ifdef __EMX__ /* OS2 - write in binary mode. */ 1200141cc406Sopenharmony_ci _fsetmode (ofp, "b"); 1201141cc406Sopenharmony_ci#endif 1202141cc406Sopenharmony_ci} 1203141cc406Sopenharmony_ci 1204141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1205141cc406Sopenharmony_cistatic void 1206141cc406Sopenharmony_ciwrite_png_header (SANE_Frame format, int width, int height, int depth, int dpi, const char * icc_profile, FILE *ofp, png_structp* png_ptr, png_infop* info_ptr) 1207141cc406Sopenharmony_ci{ 1208141cc406Sopenharmony_ci int color_type; 1209141cc406Sopenharmony_ci /* PNG does not have imperial reference units, so we must convert to metric. */ 1210141cc406Sopenharmony_ci /* There are nominally 39.3700787401575 inches in a meter. */ 1211141cc406Sopenharmony_ci const double pixels_per_meter = dpi * 39.3700787401575; 1212141cc406Sopenharmony_ci size_t icc_size = 0; 1213141cc406Sopenharmony_ci void *icc_buffer; 1214141cc406Sopenharmony_ci 1215141cc406Sopenharmony_ci *png_ptr = png_create_write_struct 1216141cc406Sopenharmony_ci (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 1217141cc406Sopenharmony_ci if (!*png_ptr) { 1218141cc406Sopenharmony_ci fprintf(stderr, "png_create_write_struct failed\n"); 1219141cc406Sopenharmony_ci exit(1); 1220141cc406Sopenharmony_ci } 1221141cc406Sopenharmony_ci *info_ptr = png_create_info_struct(*png_ptr); 1222141cc406Sopenharmony_ci if (!*info_ptr) { 1223141cc406Sopenharmony_ci fprintf(stderr, "png_create_info_struct failed\n"); 1224141cc406Sopenharmony_ci exit(1); 1225141cc406Sopenharmony_ci } 1226141cc406Sopenharmony_ci png_init_io(*png_ptr, ofp); 1227141cc406Sopenharmony_ci 1228141cc406Sopenharmony_ci switch (format) 1229141cc406Sopenharmony_ci { 1230141cc406Sopenharmony_ci case SANE_FRAME_RED: 1231141cc406Sopenharmony_ci case SANE_FRAME_GREEN: 1232141cc406Sopenharmony_ci case SANE_FRAME_BLUE: 1233141cc406Sopenharmony_ci case SANE_FRAME_RGB: 1234141cc406Sopenharmony_ci color_type = PNG_COLOR_TYPE_RGB; 1235141cc406Sopenharmony_ci break; 1236141cc406Sopenharmony_ci 1237141cc406Sopenharmony_ci default: 1238141cc406Sopenharmony_ci color_type = PNG_COLOR_TYPE_GRAY; 1239141cc406Sopenharmony_ci break; 1240141cc406Sopenharmony_ci } 1241141cc406Sopenharmony_ci 1242141cc406Sopenharmony_ci png_set_IHDR(*png_ptr, *info_ptr, width, height, 1243141cc406Sopenharmony_ci depth, color_type, PNG_INTERLACE_NONE, 1244141cc406Sopenharmony_ci PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 1245141cc406Sopenharmony_ci 1246141cc406Sopenharmony_ci png_set_pHYs(*png_ptr, *info_ptr, 1247141cc406Sopenharmony_ci pixels_per_meter, pixels_per_meter, 1248141cc406Sopenharmony_ci PNG_RESOLUTION_METER); 1249141cc406Sopenharmony_ci 1250141cc406Sopenharmony_ci if (icc_profile) 1251141cc406Sopenharmony_ci { 1252141cc406Sopenharmony_ci icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size); 1253141cc406Sopenharmony_ci if (icc_size > 0) 1254141cc406Sopenharmony_ci { 1255141cc406Sopenharmony_ci /* libpng will abort if the profile and image colour spaces do not match*/ 1256141cc406Sopenharmony_ci /* The data colour space field is at bytes 16 to 20 in an ICC profile */ 1257141cc406Sopenharmony_ci /* see: ICC.1:2010 § 7.2.6 */ 1258141cc406Sopenharmony_ci int is_gray_profile = strncmp((char *) icc_buffer + 16, "GRAY", 4) == 0; 1259141cc406Sopenharmony_ci int is_rgb_profile = strncmp((char *) icc_buffer + 16, "RGB ", 4) == 0; 1260141cc406Sopenharmony_ci if ((is_gray_profile && color_type == PNG_COLOR_TYPE_GRAY) || 1261141cc406Sopenharmony_ci (is_rgb_profile && color_type == PNG_COLOR_TYPE_RGB)) 1262141cc406Sopenharmony_ci { 1263141cc406Sopenharmony_ci png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size); 1264141cc406Sopenharmony_ci } 1265141cc406Sopenharmony_ci else 1266141cc406Sopenharmony_ci { 1267141cc406Sopenharmony_ci if (is_gray_profile) 1268141cc406Sopenharmony_ci { 1269141cc406Sopenharmony_ci fprintf(stderr, "Ignoring 'GRAY' space ICC profile because the image is RGB.\n"); 1270141cc406Sopenharmony_ci } 1271141cc406Sopenharmony_ci if (is_rgb_profile) 1272141cc406Sopenharmony_ci { 1273141cc406Sopenharmony_ci fprintf(stderr, "Ignoring 'RGB ' space ICC profile because the image is Grayscale.\n"); 1274141cc406Sopenharmony_ci } 1275141cc406Sopenharmony_ci } 1276141cc406Sopenharmony_ci free(icc_buffer); 1277141cc406Sopenharmony_ci } 1278141cc406Sopenharmony_ci } 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ci png_write_info(*png_ptr, *info_ptr); 1281141cc406Sopenharmony_ci} 1282141cc406Sopenharmony_ci#endif 1283141cc406Sopenharmony_ci 1284141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1285141cc406Sopenharmony_cistatic void 1286141cc406Sopenharmony_ciwrite_jpeg_header (SANE_Frame format, int width, int height, int dpi, FILE *ofp, 1287141cc406Sopenharmony_ci struct jpeg_compress_struct *cinfo, 1288141cc406Sopenharmony_ci struct jpeg_error_mgr *jerr) 1289141cc406Sopenharmony_ci{ 1290141cc406Sopenharmony_ci cinfo->err = jpeg_std_error(jerr); 1291141cc406Sopenharmony_ci jpeg_create_compress(cinfo); 1292141cc406Sopenharmony_ci jpeg_stdio_dest(cinfo, ofp); 1293141cc406Sopenharmony_ci 1294141cc406Sopenharmony_ci cinfo->image_width = width; 1295141cc406Sopenharmony_ci cinfo->image_height = height; 1296141cc406Sopenharmony_ci switch (format) 1297141cc406Sopenharmony_ci { 1298141cc406Sopenharmony_ci case SANE_FRAME_RED: 1299141cc406Sopenharmony_ci case SANE_FRAME_GREEN: 1300141cc406Sopenharmony_ci case SANE_FRAME_BLUE: 1301141cc406Sopenharmony_ci case SANE_FRAME_RGB: 1302141cc406Sopenharmony_ci cinfo->in_color_space = JCS_RGB; 1303141cc406Sopenharmony_ci cinfo->input_components = 3; 1304141cc406Sopenharmony_ci break; 1305141cc406Sopenharmony_ci 1306141cc406Sopenharmony_ci default: 1307141cc406Sopenharmony_ci cinfo->in_color_space = JCS_GRAYSCALE; 1308141cc406Sopenharmony_ci cinfo->input_components = 1; 1309141cc406Sopenharmony_ci break; 1310141cc406Sopenharmony_ci } 1311141cc406Sopenharmony_ci 1312141cc406Sopenharmony_ci jpeg_set_defaults(cinfo); 1313141cc406Sopenharmony_ci /* jpeg_set_defaults overrides density, be careful. */ 1314141cc406Sopenharmony_ci cinfo->density_unit = 1; /* Inches */ 1315141cc406Sopenharmony_ci cinfo->X_density = cinfo->Y_density = dpi; 1316141cc406Sopenharmony_ci cinfo->write_JFIF_header = TRUE; 1317141cc406Sopenharmony_ci 1318141cc406Sopenharmony_ci jpeg_set_quality(cinfo, 75, TRUE); 1319141cc406Sopenharmony_ci jpeg_start_compress(cinfo, TRUE); 1320141cc406Sopenharmony_ci} 1321141cc406Sopenharmony_ci#endif 1322141cc406Sopenharmony_ci 1323141cc406Sopenharmony_cistatic void * 1324141cc406Sopenharmony_ciadvance (Image * image) 1325141cc406Sopenharmony_ci{ 1326141cc406Sopenharmony_ci if (++image->x >= image->width) 1327141cc406Sopenharmony_ci { 1328141cc406Sopenharmony_ci image->x = 0; 1329141cc406Sopenharmony_ci if (++image->y >= image->height || !image->data) 1330141cc406Sopenharmony_ci { 1331141cc406Sopenharmony_ci size_t old_size = 0, new_size; 1332141cc406Sopenharmony_ci 1333141cc406Sopenharmony_ci if (image->data) 1334141cc406Sopenharmony_ci old_size = image->height * image->width * image->num_channels; 1335141cc406Sopenharmony_ci 1336141cc406Sopenharmony_ci image->height += STRIP_HEIGHT; 1337141cc406Sopenharmony_ci new_size = image->height * image->width * image->num_channels; 1338141cc406Sopenharmony_ci 1339141cc406Sopenharmony_ci if (image->data) 1340141cc406Sopenharmony_ci image->data = realloc (image->data, new_size); 1341141cc406Sopenharmony_ci else 1342141cc406Sopenharmony_ci image->data = malloc (new_size); 1343141cc406Sopenharmony_ci if (image->data) 1344141cc406Sopenharmony_ci memset (image->data + old_size, 0, new_size - old_size); 1345141cc406Sopenharmony_ci } 1346141cc406Sopenharmony_ci } 1347141cc406Sopenharmony_ci if (!image->data) 1348141cc406Sopenharmony_ci fprintf (stderr, "%s: can't allocate image buffer (%dx%d)\n", 1349141cc406Sopenharmony_ci prog_name, image->width, image->height); 1350141cc406Sopenharmony_ci return image->data; 1351141cc406Sopenharmony_ci} 1352141cc406Sopenharmony_ci 1353141cc406Sopenharmony_cistatic SANE_Status 1354141cc406Sopenharmony_ciscan_it (FILE *ofp, void* pw) 1355141cc406Sopenharmony_ci{ 1356141cc406Sopenharmony_ci int i, len, first_frame = 1, offset = 0, must_buffer = 0; 1357141cc406Sopenharmony_ci uint64_t hundred_percent = 0; 1358141cc406Sopenharmony_ci SANE_Byte min = 0xff, max = 0; 1359141cc406Sopenharmony_ci SANE_Parameters parm; 1360141cc406Sopenharmony_ci SANE_Status status; 1361141cc406Sopenharmony_ci Image image = { 0, 0, 0, 0, 0, 0 }; 1362141cc406Sopenharmony_ci static const char *format_name[] = { 1363141cc406Sopenharmony_ci "gray", "RGB", "red", "green", "blue" 1364141cc406Sopenharmony_ci }; 1365141cc406Sopenharmony_ci uint64_t total_bytes = 0, expected_bytes; 1366141cc406Sopenharmony_ci SANE_Int hang_over = -1; 1367141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1368141cc406Sopenharmony_ci int pngrow = 0; 1369141cc406Sopenharmony_ci png_bytep pngbuf = NULL; 1370141cc406Sopenharmony_ci png_structp png_ptr; 1371141cc406Sopenharmony_ci png_infop info_ptr; 1372141cc406Sopenharmony_ci#endif 1373141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1374141cc406Sopenharmony_ci int jpegrow = 0; 1375141cc406Sopenharmony_ci JSAMPLE *jpegbuf = NULL; 1376141cc406Sopenharmony_ci struct jpeg_compress_struct cinfo; 1377141cc406Sopenharmony_ci struct jpeg_error_mgr jerr; 1378141cc406Sopenharmony_ci#endif 1379141cc406Sopenharmony_ci 1380141cc406Sopenharmony_ci (void)pw; 1381141cc406Sopenharmony_ci 1382141cc406Sopenharmony_ci do 1383141cc406Sopenharmony_ci { 1384141cc406Sopenharmony_ci if (!first_frame) 1385141cc406Sopenharmony_ci { 1386141cc406Sopenharmony_ci#ifdef SANE_STATUS_WARMING_UP 1387141cc406Sopenharmony_ci do 1388141cc406Sopenharmony_ci { 1389141cc406Sopenharmony_ci status = sane_start (device); 1390141cc406Sopenharmony_ci } 1391141cc406Sopenharmony_ci while(status == SANE_STATUS_WARMING_UP); 1392141cc406Sopenharmony_ci#else 1393141cc406Sopenharmony_ci status = sane_start (device); 1394141cc406Sopenharmony_ci#endif 1395141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1396141cc406Sopenharmony_ci { 1397141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_start: %s\n", 1398141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 1399141cc406Sopenharmony_ci goto cleanup; 1400141cc406Sopenharmony_ci } 1401141cc406Sopenharmony_ci } 1402141cc406Sopenharmony_ci 1403141cc406Sopenharmony_ci status = sane_get_parameters (device, &parm); 1404141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1405141cc406Sopenharmony_ci { 1406141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_get_parameters: %s\n", 1407141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 1408141cc406Sopenharmony_ci goto cleanup; 1409141cc406Sopenharmony_ci } 1410141cc406Sopenharmony_ci 1411141cc406Sopenharmony_ci if (verbose) 1412141cc406Sopenharmony_ci { 1413141cc406Sopenharmony_ci if (first_frame) 1414141cc406Sopenharmony_ci { 1415141cc406Sopenharmony_ci if (parm.lines >= 0) 1416141cc406Sopenharmony_ci fprintf (stderr, "%s: scanning image of size %dx%d pixels at " 1417141cc406Sopenharmony_ci "%d bits/pixel\n", 1418141cc406Sopenharmony_ci prog_name, parm.pixels_per_line, parm.lines, 1419141cc406Sopenharmony_ci parm.depth * (SANE_FRAME_RGB == parm.format ? 3 : 1)); 1420141cc406Sopenharmony_ci else 1421141cc406Sopenharmony_ci fprintf (stderr, "%s: scanning image %d pixels wide and " 1422141cc406Sopenharmony_ci "variable height at %d bits/pixel\n", 1423141cc406Sopenharmony_ci prog_name, parm.pixels_per_line, 1424141cc406Sopenharmony_ci parm.depth * (SANE_FRAME_RGB == parm.format ? 3 : 1)); 1425141cc406Sopenharmony_ci } 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci fprintf (stderr, "%s: acquiring %s frame\n", prog_name, 1428141cc406Sopenharmony_ci parm.format <= SANE_FRAME_BLUE ? format_name[parm.format]:"Unknown"); 1429141cc406Sopenharmony_ci } 1430141cc406Sopenharmony_ci 1431141cc406Sopenharmony_ci if (first_frame) 1432141cc406Sopenharmony_ci { 1433141cc406Sopenharmony_ci image.num_channels = 1; 1434141cc406Sopenharmony_ci switch (parm.format) 1435141cc406Sopenharmony_ci { 1436141cc406Sopenharmony_ci case SANE_FRAME_RED: 1437141cc406Sopenharmony_ci case SANE_FRAME_GREEN: 1438141cc406Sopenharmony_ci case SANE_FRAME_BLUE: 1439141cc406Sopenharmony_ci assert (parm.depth == 8); 1440141cc406Sopenharmony_ci must_buffer = 1; 1441141cc406Sopenharmony_ci offset = parm.format - SANE_FRAME_RED; 1442141cc406Sopenharmony_ci image.num_channels = 3; 1443141cc406Sopenharmony_ci break; 1444141cc406Sopenharmony_ci 1445141cc406Sopenharmony_ci case SANE_FRAME_RGB: 1446141cc406Sopenharmony_ci assert ((parm.depth == 8) || (parm.depth == 16)); 1447141cc406Sopenharmony_ci case SANE_FRAME_GRAY: 1448141cc406Sopenharmony_ci assert ((parm.depth == 1) || (parm.depth == 8) 1449141cc406Sopenharmony_ci || (parm.depth == 16)); 1450141cc406Sopenharmony_ci if (parm.lines < 0) 1451141cc406Sopenharmony_ci { 1452141cc406Sopenharmony_ci must_buffer = 1; 1453141cc406Sopenharmony_ci offset = 0; 1454141cc406Sopenharmony_ci } 1455141cc406Sopenharmony_ci else 1456141cc406Sopenharmony_ci switch(output_format) 1457141cc406Sopenharmony_ci { 1458141cc406Sopenharmony_ci case OUTPUT_TIFF: 1459141cc406Sopenharmony_ci sanei_write_tiff_header (parm.format, 1460141cc406Sopenharmony_ci parm.pixels_per_line, parm.lines, 1461141cc406Sopenharmony_ci parm.depth, resolution_value, 1462141cc406Sopenharmony_ci icc_profile, ofp); 1463141cc406Sopenharmony_ci break; 1464141cc406Sopenharmony_ci case OUTPUT_PNM: 1465141cc406Sopenharmony_ci write_pnm_header (parm.format, parm.pixels_per_line, 1466141cc406Sopenharmony_ci parm.lines, parm.depth, ofp); 1467141cc406Sopenharmony_ci break; 1468141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1469141cc406Sopenharmony_ci case OUTPUT_PNG: 1470141cc406Sopenharmony_ci write_png_header (parm.format, parm.pixels_per_line, 1471141cc406Sopenharmony_ci parm.lines, parm.depth, resolution_value, 1472141cc406Sopenharmony_ci icc_profile, ofp, &png_ptr, &info_ptr); 1473141cc406Sopenharmony_ci break; 1474141cc406Sopenharmony_ci#endif 1475141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1476141cc406Sopenharmony_ci case OUTPUT_PDF: 1477141cc406Sopenharmony_ci sane_pdf_start_page ( pw, parm.pixels_per_line, parm.lines, 1478141cc406Sopenharmony_ci resolution_value, SANE_PDF_IMAGE_COLOR, 1479141cc406Sopenharmony_ci SANE_PDF_ROTATE_OFF); 1480141cc406Sopenharmony_ci write_jpeg_header (parm.format, parm.pixels_per_line, 1481141cc406Sopenharmony_ci parm.lines, resolution_value, 1482141cc406Sopenharmony_ci ofp, &cinfo, &jerr); 1483141cc406Sopenharmony_ci break; 1484141cc406Sopenharmony_ci case OUTPUT_JPEG: 1485141cc406Sopenharmony_ci write_jpeg_header (parm.format, parm.pixels_per_line, 1486141cc406Sopenharmony_ci parm.lines, resolution_value, 1487141cc406Sopenharmony_ci ofp, &cinfo, &jerr); 1488141cc406Sopenharmony_ci break; 1489141cc406Sopenharmony_ci#endif 1490141cc406Sopenharmony_ci } 1491141cc406Sopenharmony_ci break; 1492141cc406Sopenharmony_ci 1493141cc406Sopenharmony_ci default: 1494141cc406Sopenharmony_ci break; 1495141cc406Sopenharmony_ci } 1496141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1497141cc406Sopenharmony_ci if(output_format == OUTPUT_PNG) 1498141cc406Sopenharmony_ci pngbuf = malloc(parm.bytes_per_line); 1499141cc406Sopenharmony_ci#endif 1500141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1501141cc406Sopenharmony_ci if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) 1502141cc406Sopenharmony_ci jpegbuf = malloc(parm.bytes_per_line); 1503141cc406Sopenharmony_ci#endif 1504141cc406Sopenharmony_ci 1505141cc406Sopenharmony_ci if (must_buffer) 1506141cc406Sopenharmony_ci { 1507141cc406Sopenharmony_ci /* We're either scanning a multi-frame image or the 1508141cc406Sopenharmony_ci scanner doesn't know what the eventual image height 1509141cc406Sopenharmony_ci will be (common for hand-held scanners). In either 1510141cc406Sopenharmony_ci case, we need to buffer all data before we can write 1511141cc406Sopenharmony_ci the image. */ 1512141cc406Sopenharmony_ci image.width = parm.bytes_per_line; 1513141cc406Sopenharmony_ci 1514141cc406Sopenharmony_ci if (parm.lines >= 0) 1515141cc406Sopenharmony_ci /* See advance(); we allocate one extra line so we 1516141cc406Sopenharmony_ci don't end up realloc'ing in when the image has been 1517141cc406Sopenharmony_ci filled in. */ 1518141cc406Sopenharmony_ci image.height = parm.lines - STRIP_HEIGHT + 1; 1519141cc406Sopenharmony_ci else 1520141cc406Sopenharmony_ci image.height = 0; 1521141cc406Sopenharmony_ci 1522141cc406Sopenharmony_ci image.x = image.width - 1; 1523141cc406Sopenharmony_ci image.y = -1; 1524141cc406Sopenharmony_ci if (!advance (&image)) 1525141cc406Sopenharmony_ci { 1526141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 1527141cc406Sopenharmony_ci goto cleanup; 1528141cc406Sopenharmony_ci } 1529141cc406Sopenharmony_ci } 1530141cc406Sopenharmony_ci } 1531141cc406Sopenharmony_ci else 1532141cc406Sopenharmony_ci { 1533141cc406Sopenharmony_ci assert (parm.format >= SANE_FRAME_RED 1534141cc406Sopenharmony_ci && parm.format <= SANE_FRAME_BLUE); 1535141cc406Sopenharmony_ci offset = parm.format - SANE_FRAME_RED; 1536141cc406Sopenharmony_ci image.x = image.y = 0; 1537141cc406Sopenharmony_ci } 1538141cc406Sopenharmony_ci hundred_percent = ((uint64_t)parm.bytes_per_line) * parm.lines 1539141cc406Sopenharmony_ci * ((parm.format == SANE_FRAME_RGB || parm.format == SANE_FRAME_GRAY) ? 1:3); 1540141cc406Sopenharmony_ci 1541141cc406Sopenharmony_ci while (1) 1542141cc406Sopenharmony_ci { 1543141cc406Sopenharmony_ci double progr; 1544141cc406Sopenharmony_ci status = sane_read (device, buffer, buffer_size, &len); 1545141cc406Sopenharmony_ci total_bytes += (SANE_Word) len; 1546141cc406Sopenharmony_ci progr = ((total_bytes * 100.) / (double) hundred_percent); 1547141cc406Sopenharmony_ci if (progr > 100.) 1548141cc406Sopenharmony_ci progr = 100.; 1549141cc406Sopenharmony_ci if (progress) 1550141cc406Sopenharmony_ci { 1551141cc406Sopenharmony_ci if (parm.lines >= 0) 1552141cc406Sopenharmony_ci fprintf(stderr, "Progress: %3.1f%%\r", progr); 1553141cc406Sopenharmony_ci else 1554141cc406Sopenharmony_ci fprintf(stderr, "Progress: (unknown)\r"); 1555141cc406Sopenharmony_ci } 1556141cc406Sopenharmony_ci 1557141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1558141cc406Sopenharmony_ci { 1559141cc406Sopenharmony_ci if (verbose && parm.depth == 8) 1560141cc406Sopenharmony_ci fprintf (stderr, "%s: min/max graylevel value = %d/%d\n", 1561141cc406Sopenharmony_ci prog_name, min, max); 1562141cc406Sopenharmony_ci if (status != SANE_STATUS_EOF) 1563141cc406Sopenharmony_ci { 1564141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_read: %s\n", 1565141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 1566141cc406Sopenharmony_ci return status; 1567141cc406Sopenharmony_ci } 1568141cc406Sopenharmony_ci break; 1569141cc406Sopenharmony_ci } 1570141cc406Sopenharmony_ci 1571141cc406Sopenharmony_ci if (must_buffer) 1572141cc406Sopenharmony_ci { 1573141cc406Sopenharmony_ci switch (parm.format) 1574141cc406Sopenharmony_ci { 1575141cc406Sopenharmony_ci case SANE_FRAME_RED: 1576141cc406Sopenharmony_ci case SANE_FRAME_GREEN: 1577141cc406Sopenharmony_ci case SANE_FRAME_BLUE: 1578141cc406Sopenharmony_ci image.num_channels = 3; 1579141cc406Sopenharmony_ci for (i = 0; i < len; ++i) 1580141cc406Sopenharmony_ci { 1581141cc406Sopenharmony_ci image.data[offset + 3 * i] = buffer[i]; 1582141cc406Sopenharmony_ci if (!advance (&image)) 1583141cc406Sopenharmony_ci { 1584141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 1585141cc406Sopenharmony_ci goto cleanup; 1586141cc406Sopenharmony_ci } 1587141cc406Sopenharmony_ci } 1588141cc406Sopenharmony_ci offset += 3 * len; 1589141cc406Sopenharmony_ci break; 1590141cc406Sopenharmony_ci 1591141cc406Sopenharmony_ci case SANE_FRAME_RGB: 1592141cc406Sopenharmony_ci image.num_channels = 1; 1593141cc406Sopenharmony_ci for (i = 0; i < len; ++i) 1594141cc406Sopenharmony_ci { 1595141cc406Sopenharmony_ci image.data[offset + i] = buffer[i]; 1596141cc406Sopenharmony_ci if (!advance (&image)) 1597141cc406Sopenharmony_ci { 1598141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 1599141cc406Sopenharmony_ci goto cleanup; 1600141cc406Sopenharmony_ci } 1601141cc406Sopenharmony_ci } 1602141cc406Sopenharmony_ci offset += len; 1603141cc406Sopenharmony_ci break; 1604141cc406Sopenharmony_ci 1605141cc406Sopenharmony_ci case SANE_FRAME_GRAY: 1606141cc406Sopenharmony_ci image.num_channels = 1; 1607141cc406Sopenharmony_ci for (i = 0; i < len; ++i) 1608141cc406Sopenharmony_ci { 1609141cc406Sopenharmony_ci image.data[offset + i] = buffer[i]; 1610141cc406Sopenharmony_ci if (!advance (&image)) 1611141cc406Sopenharmony_ci { 1612141cc406Sopenharmony_ci status = SANE_STATUS_NO_MEM; 1613141cc406Sopenharmony_ci goto cleanup; 1614141cc406Sopenharmony_ci } 1615141cc406Sopenharmony_ci } 1616141cc406Sopenharmony_ci offset += len; 1617141cc406Sopenharmony_ci break; 1618141cc406Sopenharmony_ci 1619141cc406Sopenharmony_ci default: 1620141cc406Sopenharmony_ci break; 1621141cc406Sopenharmony_ci } 1622141cc406Sopenharmony_ci } 1623141cc406Sopenharmony_ci else /* ! must_buffer */ 1624141cc406Sopenharmony_ci { 1625141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1626141cc406Sopenharmony_ci if (output_format == OUTPUT_PNG) 1627141cc406Sopenharmony_ci { 1628141cc406Sopenharmony_ci int i = 0; 1629141cc406Sopenharmony_ci int left = len; 1630141cc406Sopenharmony_ci while(pngrow + left >= parm.bytes_per_line) 1631141cc406Sopenharmony_ci { 1632141cc406Sopenharmony_ci memcpy(pngbuf + pngrow, buffer + i, parm.bytes_per_line - pngrow); 1633141cc406Sopenharmony_ci if(parm.depth == 1) 1634141cc406Sopenharmony_ci { 1635141cc406Sopenharmony_ci int j; 1636141cc406Sopenharmony_ci for(j = 0; j < parm.bytes_per_line; j++) 1637141cc406Sopenharmony_ci pngbuf[j] = ~pngbuf[j]; 1638141cc406Sopenharmony_ci } 1639141cc406Sopenharmony_ci#ifndef WORDS_BIGENDIAN 1640141cc406Sopenharmony_ci /* SANE is endian-native, PNG is big-endian, */ 1641141cc406Sopenharmony_ci /* see: https://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order */ 1642141cc406Sopenharmony_ci if (parm.depth == 16) 1643141cc406Sopenharmony_ci { 1644141cc406Sopenharmony_ci int j; 1645141cc406Sopenharmony_ci for (j = 0; j < parm.bytes_per_line; j += 2) 1646141cc406Sopenharmony_ci { 1647141cc406Sopenharmony_ci SANE_Byte LSB; 1648141cc406Sopenharmony_ci LSB = pngbuf[j]; 1649141cc406Sopenharmony_ci pngbuf[j] = pngbuf[j + 1]; 1650141cc406Sopenharmony_ci pngbuf[j + 1] = LSB; 1651141cc406Sopenharmony_ci } 1652141cc406Sopenharmony_ci } 1653141cc406Sopenharmony_ci#endif 1654141cc406Sopenharmony_ci png_write_row(png_ptr, pngbuf); 1655141cc406Sopenharmony_ci i += parm.bytes_per_line - pngrow; 1656141cc406Sopenharmony_ci left -= parm.bytes_per_line - pngrow; 1657141cc406Sopenharmony_ci pngrow = 0; 1658141cc406Sopenharmony_ci } 1659141cc406Sopenharmony_ci memcpy(pngbuf + pngrow, buffer + i, left); 1660141cc406Sopenharmony_ci pngrow += left; 1661141cc406Sopenharmony_ci } 1662141cc406Sopenharmony_ci else 1663141cc406Sopenharmony_ci#endif 1664141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1665141cc406Sopenharmony_ci if (output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) 1666141cc406Sopenharmony_ci { 1667141cc406Sopenharmony_ci int i = 0; 1668141cc406Sopenharmony_ci int left = len; 1669141cc406Sopenharmony_ci while(jpegrow + left >= parm.bytes_per_line) 1670141cc406Sopenharmony_ci { 1671141cc406Sopenharmony_ci memcpy(jpegbuf + jpegrow, buffer + i, parm.bytes_per_line - jpegrow); 1672141cc406Sopenharmony_ci if(parm.depth == 1) 1673141cc406Sopenharmony_ci { 1674141cc406Sopenharmony_ci int col1, col8; 1675141cc406Sopenharmony_ci JSAMPLE *buf8 = malloc(parm.bytes_per_line * 8); 1676141cc406Sopenharmony_ci for(col1 = 0; col1 < parm.bytes_per_line; col1++) 1677141cc406Sopenharmony_ci for(col8 = 0; col8 < 8; col8++) 1678141cc406Sopenharmony_ci buf8[col1 * 8 + col8] = jpegbuf[col1] & (1 << (8 - col8 - 1)) ? 0 : 0xff; 1679141cc406Sopenharmony_ci jpeg_write_scanlines(&cinfo, &buf8, 1); 1680141cc406Sopenharmony_ci free(buf8); 1681141cc406Sopenharmony_ci } else { 1682141cc406Sopenharmony_ci jpeg_write_scanlines(&cinfo, &jpegbuf, 1); 1683141cc406Sopenharmony_ci } 1684141cc406Sopenharmony_ci i += parm.bytes_per_line - jpegrow; 1685141cc406Sopenharmony_ci left -= parm.bytes_per_line - jpegrow; 1686141cc406Sopenharmony_ci jpegrow = 0; 1687141cc406Sopenharmony_ci } 1688141cc406Sopenharmony_ci memcpy(jpegbuf + jpegrow, buffer + i, left); 1689141cc406Sopenharmony_ci jpegrow += left; 1690141cc406Sopenharmony_ci } 1691141cc406Sopenharmony_ci else 1692141cc406Sopenharmony_ci#endif 1693141cc406Sopenharmony_ci if ((output_format == OUTPUT_TIFF) || (parm.depth != 16)) 1694141cc406Sopenharmony_ci fwrite (buffer, 1, len, ofp); 1695141cc406Sopenharmony_ci else 1696141cc406Sopenharmony_ci { 1697141cc406Sopenharmony_ci#if !defined(WORDS_BIGENDIAN) 1698141cc406Sopenharmony_ci int i, start = 0; 1699141cc406Sopenharmony_ci 1700141cc406Sopenharmony_ci /* check if we have saved one byte from the last sane_read */ 1701141cc406Sopenharmony_ci if (hang_over > -1) 1702141cc406Sopenharmony_ci { 1703141cc406Sopenharmony_ci if (len > 0) 1704141cc406Sopenharmony_ci { 1705141cc406Sopenharmony_ci fwrite (buffer, 1, 1, ofp); 1706141cc406Sopenharmony_ci buffer[0] = (SANE_Byte) hang_over; 1707141cc406Sopenharmony_ci hang_over = -1; 1708141cc406Sopenharmony_ci start = 1; 1709141cc406Sopenharmony_ci } 1710141cc406Sopenharmony_ci } 1711141cc406Sopenharmony_ci /* now do the byte-swapping */ 1712141cc406Sopenharmony_ci for (i = start; i < (len - 1); i += 2) 1713141cc406Sopenharmony_ci { 1714141cc406Sopenharmony_ci unsigned char LSB; 1715141cc406Sopenharmony_ci LSB = buffer[i]; 1716141cc406Sopenharmony_ci buffer[i] = buffer[i + 1]; 1717141cc406Sopenharmony_ci buffer[i + 1] = LSB; 1718141cc406Sopenharmony_ci } 1719141cc406Sopenharmony_ci /* check if we have an odd number of bytes */ 1720141cc406Sopenharmony_ci if (((len - start) % 2) != 0) 1721141cc406Sopenharmony_ci { 1722141cc406Sopenharmony_ci hang_over = buffer[len - 1]; 1723141cc406Sopenharmony_ci len--; 1724141cc406Sopenharmony_ci } 1725141cc406Sopenharmony_ci#endif 1726141cc406Sopenharmony_ci fwrite (buffer, 1, len, ofp); 1727141cc406Sopenharmony_ci } 1728141cc406Sopenharmony_ci } 1729141cc406Sopenharmony_ci 1730141cc406Sopenharmony_ci if (verbose && parm.depth == 8) 1731141cc406Sopenharmony_ci { 1732141cc406Sopenharmony_ci for (i = 0; i < len; ++i) 1733141cc406Sopenharmony_ci if (buffer[i] >= max) 1734141cc406Sopenharmony_ci max = buffer[i]; 1735141cc406Sopenharmony_ci else if (buffer[i] < min) 1736141cc406Sopenharmony_ci min = buffer[i]; 1737141cc406Sopenharmony_ci } 1738141cc406Sopenharmony_ci } 1739141cc406Sopenharmony_ci first_frame = 0; 1740141cc406Sopenharmony_ci } 1741141cc406Sopenharmony_ci while (!parm.last_frame); 1742141cc406Sopenharmony_ci 1743141cc406Sopenharmony_ci if (must_buffer) 1744141cc406Sopenharmony_ci { 1745141cc406Sopenharmony_ci image.height = image.y; 1746141cc406Sopenharmony_ci 1747141cc406Sopenharmony_ci switch(output_format) { 1748141cc406Sopenharmony_ci case OUTPUT_TIFF: 1749141cc406Sopenharmony_ci sanei_write_tiff_header (parm.format, parm.pixels_per_line, 1750141cc406Sopenharmony_ci image.height, parm.depth, resolution_value, 1751141cc406Sopenharmony_ci icc_profile, ofp); 1752141cc406Sopenharmony_ci break; 1753141cc406Sopenharmony_ci case OUTPUT_PNM: 1754141cc406Sopenharmony_ci write_pnm_header (parm.format, parm.pixels_per_line, 1755141cc406Sopenharmony_ci image.height, parm.depth, ofp); 1756141cc406Sopenharmony_ci break; 1757141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1758141cc406Sopenharmony_ci case OUTPUT_PNG: 1759141cc406Sopenharmony_ci write_png_header (parm.format, parm.pixels_per_line, 1760141cc406Sopenharmony_ci image.height, parm.depth, resolution_value, 1761141cc406Sopenharmony_ci icc_profile, ofp, &png_ptr, &info_ptr); 1762141cc406Sopenharmony_ci break; 1763141cc406Sopenharmony_ci#endif 1764141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1765141cc406Sopenharmony_ci case OUTPUT_PDF: 1766141cc406Sopenharmony_ci sane_pdf_start_page ( pw, parm.pixels_per_line, parm.lines, 1767141cc406Sopenharmony_ci resolution_value, SANE_PDF_IMAGE_COLOR, 1768141cc406Sopenharmony_ci SANE_PDF_ROTATE_OFF); 1769141cc406Sopenharmony_ci write_jpeg_header (parm.format, parm.pixels_per_line, 1770141cc406Sopenharmony_ci parm.lines, resolution_value, 1771141cc406Sopenharmony_ci ofp, &cinfo, &jerr); 1772141cc406Sopenharmony_ci break; 1773141cc406Sopenharmony_ci case OUTPUT_JPEG: 1774141cc406Sopenharmony_ci write_jpeg_header (parm.format, parm.pixels_per_line, 1775141cc406Sopenharmony_ci parm.lines, resolution_value, 1776141cc406Sopenharmony_ci ofp, &cinfo, &jerr); 1777141cc406Sopenharmony_ci break; 1778141cc406Sopenharmony_ci#endif 1779141cc406Sopenharmony_ci } 1780141cc406Sopenharmony_ci 1781141cc406Sopenharmony_ci#if !defined(WORDS_BIGENDIAN) 1782141cc406Sopenharmony_ci /* multibyte pnm file may need byte swap to LE */ 1783141cc406Sopenharmony_ci /* FIXME: other bit depths? */ 1784141cc406Sopenharmony_ci if (output_format != OUTPUT_TIFF && parm.depth == 16) 1785141cc406Sopenharmony_ci { 1786141cc406Sopenharmony_ci int i; 1787141cc406Sopenharmony_ci for (i = 0; i < image.height * image.width; i += 2) 1788141cc406Sopenharmony_ci { 1789141cc406Sopenharmony_ci unsigned char LSB; 1790141cc406Sopenharmony_ci LSB = image.data[i]; 1791141cc406Sopenharmony_ci image.data[i] = image.data[i + 1]; 1792141cc406Sopenharmony_ci image.data[i + 1] = LSB; 1793141cc406Sopenharmony_ci } 1794141cc406Sopenharmony_ci } 1795141cc406Sopenharmony_ci#endif 1796141cc406Sopenharmony_ci 1797141cc406Sopenharmony_ci fwrite (image.data, 1, image.height * image.width * image.num_channels, ofp); 1798141cc406Sopenharmony_ci } 1799141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1800141cc406Sopenharmony_ci if(output_format == OUTPUT_PNG) 1801141cc406Sopenharmony_ci png_write_end(png_ptr, info_ptr); 1802141cc406Sopenharmony_ci#endif 1803141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1804141cc406Sopenharmony_ci if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) 1805141cc406Sopenharmony_ci jpeg_finish_compress(&cinfo); 1806141cc406Sopenharmony_ci#endif 1807141cc406Sopenharmony_ci 1808141cc406Sopenharmony_ci /* flush the output buffer */ 1809141cc406Sopenharmony_ci fflush( ofp ); 1810141cc406Sopenharmony_ci 1811141cc406Sopenharmony_cicleanup: 1812141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 1813141cc406Sopenharmony_ci if(output_format == OUTPUT_PNG) { 1814141cc406Sopenharmony_ci png_destroy_write_struct(&png_ptr, &info_ptr); 1815141cc406Sopenharmony_ci free(pngbuf); 1816141cc406Sopenharmony_ci } 1817141cc406Sopenharmony_ci#endif 1818141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 1819141cc406Sopenharmony_ci if(output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF) { 1820141cc406Sopenharmony_ci jpeg_destroy_compress(&cinfo); 1821141cc406Sopenharmony_ci free(jpegbuf); 1822141cc406Sopenharmony_ci } 1823141cc406Sopenharmony_ci#endif 1824141cc406Sopenharmony_ci if (image.data) 1825141cc406Sopenharmony_ci free (image.data); 1826141cc406Sopenharmony_ci 1827141cc406Sopenharmony_ci 1828141cc406Sopenharmony_ci expected_bytes = ((uint64_t)parm.bytes_per_line) * parm.lines * 1829141cc406Sopenharmony_ci ((parm.format == SANE_FRAME_RGB 1830141cc406Sopenharmony_ci || parm.format == SANE_FRAME_GRAY) ? 1 : 3); 1831141cc406Sopenharmony_ci if (parm.lines < 0) 1832141cc406Sopenharmony_ci expected_bytes = 0; 1833141cc406Sopenharmony_ci if (total_bytes > expected_bytes && expected_bytes != 0) 1834141cc406Sopenharmony_ci { 1835141cc406Sopenharmony_ci fprintf (stderr, 1836141cc406Sopenharmony_ci "%s: WARNING: read more data than announced by backend " 1837141cc406Sopenharmony_ci "(%" PRIu64 "/%" PRIu64 ")\n", prog_name, total_bytes, expected_bytes); 1838141cc406Sopenharmony_ci } 1839141cc406Sopenharmony_ci else if (verbose) 1840141cc406Sopenharmony_ci fprintf (stderr, "%s: read %" PRIu64 " bytes in total\n", prog_name, total_bytes); 1841141cc406Sopenharmony_ci 1842141cc406Sopenharmony_ci return status; 1843141cc406Sopenharmony_ci} 1844141cc406Sopenharmony_ci 1845141cc406Sopenharmony_ci#define clean_buffer(buf,size) memset ((buf), 0x23, size) 1846141cc406Sopenharmony_ci 1847141cc406Sopenharmony_cistatic void 1848141cc406Sopenharmony_cipass_fail (int max, int len, SANE_Byte * buffer, SANE_Status status) 1849141cc406Sopenharmony_ci{ 1850141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1851141cc406Sopenharmony_ci fprintf (stderr, "FAIL Error: %s\n", sane_strstatus (status)); 1852141cc406Sopenharmony_ci else if (buffer[len] != 0x23) 1853141cc406Sopenharmony_ci { 1854141cc406Sopenharmony_ci while (len <= max && buffer[len] != 0x23) 1855141cc406Sopenharmony_ci ++len; 1856141cc406Sopenharmony_ci fprintf (stderr, "FAIL Cheat: %d bytes\n", len); 1857141cc406Sopenharmony_ci } 1858141cc406Sopenharmony_ci else if (len > max) 1859141cc406Sopenharmony_ci fprintf (stderr, "FAIL Overflow: %d bytes\n", len); 1860141cc406Sopenharmony_ci else if (len == 0) 1861141cc406Sopenharmony_ci fprintf (stderr, "FAIL No data\n"); 1862141cc406Sopenharmony_ci else 1863141cc406Sopenharmony_ci fprintf (stderr, "PASS\n"); 1864141cc406Sopenharmony_ci} 1865141cc406Sopenharmony_ci 1866141cc406Sopenharmony_cistatic SANE_Status 1867141cc406Sopenharmony_citest_it (void) 1868141cc406Sopenharmony_ci{ 1869141cc406Sopenharmony_ci int i, len; 1870141cc406Sopenharmony_ci SANE_Parameters parm; 1871141cc406Sopenharmony_ci SANE_Status status; 1872141cc406Sopenharmony_ci Image image = { 0, 0, 0, 0, 0, 0 }; 1873141cc406Sopenharmony_ci static const char *format_name[] = 1874141cc406Sopenharmony_ci { "gray", "RGB", "red", "green", "blue" }; 1875141cc406Sopenharmony_ci 1876141cc406Sopenharmony_ci#ifdef SANE_STATUS_WARMING_UP 1877141cc406Sopenharmony_ci do 1878141cc406Sopenharmony_ci { 1879141cc406Sopenharmony_ci status = sane_start (device); 1880141cc406Sopenharmony_ci } 1881141cc406Sopenharmony_ci while(status == SANE_STATUS_WARMING_UP); 1882141cc406Sopenharmony_ci#else 1883141cc406Sopenharmony_ci status = sane_start (device); 1884141cc406Sopenharmony_ci#endif 1885141cc406Sopenharmony_ci 1886141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1887141cc406Sopenharmony_ci { 1888141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_start: %s\n", 1889141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 1890141cc406Sopenharmony_ci goto cleanup; 1891141cc406Sopenharmony_ci } 1892141cc406Sopenharmony_ci 1893141cc406Sopenharmony_ci status = sane_get_parameters (device, &parm); 1894141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1895141cc406Sopenharmony_ci { 1896141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_get_parameters: %s\n", 1897141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 1898141cc406Sopenharmony_ci goto cleanup; 1899141cc406Sopenharmony_ci } 1900141cc406Sopenharmony_ci 1901141cc406Sopenharmony_ci if (parm.lines >= 0) 1902141cc406Sopenharmony_ci fprintf (stderr, "%s: scanning image of size %dx%d pixels at " 1903141cc406Sopenharmony_ci "%d bits/pixel\n", prog_name, parm.pixels_per_line, parm.lines, 1904141cc406Sopenharmony_ci parm.depth * (SANE_FRAME_RGB == parm.format ? 3 : 1)); 1905141cc406Sopenharmony_ci else 1906141cc406Sopenharmony_ci fprintf (stderr, "%s: scanning image %d pixels wide and " 1907141cc406Sopenharmony_ci "variable height at %d bits/pixel\n", 1908141cc406Sopenharmony_ci prog_name, parm.pixels_per_line, 1909141cc406Sopenharmony_ci parm.depth * (SANE_FRAME_RGB == parm.format ? 3 : 1)); 1910141cc406Sopenharmony_ci fprintf (stderr, "%s: acquiring %s frame, %d bits/sample\n", prog_name, 1911141cc406Sopenharmony_ci parm.format <= SANE_FRAME_BLUE ? format_name[parm.format]:"Unknown", 1912141cc406Sopenharmony_ci parm.depth); 1913141cc406Sopenharmony_ci 1914141cc406Sopenharmony_ci image.data = malloc (parm.bytes_per_line * 2); 1915141cc406Sopenharmony_ci 1916141cc406Sopenharmony_ci clean_buffer (image.data, parm.bytes_per_line * 2); 1917141cc406Sopenharmony_ci fprintf (stderr, "%s: reading one scanline, %d bytes...\t", prog_name, 1918141cc406Sopenharmony_ci parm.bytes_per_line); 1919141cc406Sopenharmony_ci status = sane_read (device, image.data, parm.bytes_per_line, &len); 1920141cc406Sopenharmony_ci pass_fail (parm.bytes_per_line, len, image.data, status); 1921141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1922141cc406Sopenharmony_ci goto cleanup; 1923141cc406Sopenharmony_ci 1924141cc406Sopenharmony_ci clean_buffer (image.data, parm.bytes_per_line * 2); 1925141cc406Sopenharmony_ci fprintf (stderr, "%s: reading one byte...\t\t", prog_name); 1926141cc406Sopenharmony_ci status = sane_read (device, image.data, 1, &len); 1927141cc406Sopenharmony_ci pass_fail (1, len, image.data, status); 1928141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1929141cc406Sopenharmony_ci goto cleanup; 1930141cc406Sopenharmony_ci 1931141cc406Sopenharmony_ci for (i = 2; i < parm.bytes_per_line * 2; i *= 2) 1932141cc406Sopenharmony_ci { 1933141cc406Sopenharmony_ci clean_buffer (image.data, parm.bytes_per_line * 2); 1934141cc406Sopenharmony_ci fprintf (stderr, "%s: stepped read, %d bytes... \t", prog_name, i); 1935141cc406Sopenharmony_ci status = sane_read (device, image.data, i, &len); 1936141cc406Sopenharmony_ci pass_fail (i, len, image.data, status); 1937141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1938141cc406Sopenharmony_ci goto cleanup; 1939141cc406Sopenharmony_ci } 1940141cc406Sopenharmony_ci 1941141cc406Sopenharmony_ci for (i /= 2; i > 2; i /= 2) 1942141cc406Sopenharmony_ci { 1943141cc406Sopenharmony_ci clean_buffer (image.data, parm.bytes_per_line * 2); 1944141cc406Sopenharmony_ci fprintf (stderr, "%s: stepped read, %d bytes... \t", prog_name, i - 1); 1945141cc406Sopenharmony_ci status = sane_read (device, image.data, i - 1, &len); 1946141cc406Sopenharmony_ci pass_fail (i - 1, len, image.data, status); 1947141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1948141cc406Sopenharmony_ci goto cleanup; 1949141cc406Sopenharmony_ci } 1950141cc406Sopenharmony_ci 1951141cc406Sopenharmony_cicleanup: 1952141cc406Sopenharmony_ci sane_cancel (device); 1953141cc406Sopenharmony_ci if (image.data) 1954141cc406Sopenharmony_ci free (image.data); 1955141cc406Sopenharmony_ci return status; 1956141cc406Sopenharmony_ci} 1957141cc406Sopenharmony_ci 1958141cc406Sopenharmony_ci 1959141cc406Sopenharmony_cistatic int 1960141cc406Sopenharmony_ciget_resolution (void) 1961141cc406Sopenharmony_ci{ 1962141cc406Sopenharmony_ci const SANE_Option_Descriptor *resopt; 1963141cc406Sopenharmony_ci int resol = 0; 1964141cc406Sopenharmony_ci void *val; 1965141cc406Sopenharmony_ci 1966141cc406Sopenharmony_ci if (resolution_optind < 0) 1967141cc406Sopenharmony_ci return 0; 1968141cc406Sopenharmony_ci resopt = sane_get_option_descriptor (device, resolution_optind); 1969141cc406Sopenharmony_ci if (!resopt) 1970141cc406Sopenharmony_ci return 0; 1971141cc406Sopenharmony_ci 1972141cc406Sopenharmony_ci val = alloca (resopt->size); 1973141cc406Sopenharmony_ci if (!val) 1974141cc406Sopenharmony_ci return 0; 1975141cc406Sopenharmony_ci 1976141cc406Sopenharmony_ci sane_control_option (device, resolution_optind, SANE_ACTION_GET_VALUE, val, 1977141cc406Sopenharmony_ci 0); 1978141cc406Sopenharmony_ci if (resopt->type == SANE_TYPE_INT) 1979141cc406Sopenharmony_ci resol = *(SANE_Int *) val; 1980141cc406Sopenharmony_ci else 1981141cc406Sopenharmony_ci resol = (int) (SANE_UNFIX (*(SANE_Fixed *) val) + 0.5); 1982141cc406Sopenharmony_ci 1983141cc406Sopenharmony_ci return resol; 1984141cc406Sopenharmony_ci} 1985141cc406Sopenharmony_ci 1986141cc406Sopenharmony_cistatic void 1987141cc406Sopenharmony_ciscanimage_exit (int status) 1988141cc406Sopenharmony_ci{ 1989141cc406Sopenharmony_ci if (device) 1990141cc406Sopenharmony_ci { 1991141cc406Sopenharmony_ci if (verbose > 1) 1992141cc406Sopenharmony_ci fprintf (stderr, "Closing device\n"); 1993141cc406Sopenharmony_ci sane_close (device); 1994141cc406Sopenharmony_ci } 1995141cc406Sopenharmony_ci if (verbose > 1) 1996141cc406Sopenharmony_ci fprintf (stderr, "Calling sane_exit\n"); 1997141cc406Sopenharmony_ci sane_exit (); 1998141cc406Sopenharmony_ci 1999141cc406Sopenharmony_ci if (all_options) 2000141cc406Sopenharmony_ci free (all_options); 2001141cc406Sopenharmony_ci if (option_number) 2002141cc406Sopenharmony_ci free (option_number); 2003141cc406Sopenharmony_ci if (verbose > 1) 2004141cc406Sopenharmony_ci fprintf (stderr, "scanimage: finished\n"); 2005141cc406Sopenharmony_ci exit (status); 2006141cc406Sopenharmony_ci} 2007141cc406Sopenharmony_ci 2008141cc406Sopenharmony_ci/** @brief print device options to stdout 2009141cc406Sopenharmony_ci * 2010141cc406Sopenharmony_ci * @param device struct of the opened device to describe 2011141cc406Sopenharmony_ci * @param num_dev_options number of device options 2012141cc406Sopenharmony_ci * @param ro SANE_TRUE to print read-only options 2013141cc406Sopenharmony_ci */ 2014141cc406Sopenharmony_cistatic void print_options(SANE_Device * device, SANE_Int num_dev_options, SANE_Bool ro) 2015141cc406Sopenharmony_ci{ 2016141cc406Sopenharmony_ci int i, j; 2017141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 2018141cc406Sopenharmony_ci 2019141cc406Sopenharmony_ci for (i = 1; i < num_dev_options; ++i) 2020141cc406Sopenharmony_ci { 2021141cc406Sopenharmony_ci opt = 0; 2022141cc406Sopenharmony_ci 2023141cc406Sopenharmony_ci /* scan area uses modified option struct */ 2024141cc406Sopenharmony_ci for (j = 0; j < 4; ++j) 2025141cc406Sopenharmony_ci if (i == window[j]) 2026141cc406Sopenharmony_ci opt = window_option + j; 2027141cc406Sopenharmony_ci 2028141cc406Sopenharmony_ci if (!opt) 2029141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, i); 2030141cc406Sopenharmony_ci 2031141cc406Sopenharmony_ci /* Some options from rogue backends are empty. */ 2032141cc406Sopenharmony_ci if (opt->name == NULL) 2033141cc406Sopenharmony_ci continue; 2034141cc406Sopenharmony_ci 2035141cc406Sopenharmony_ci if (ro || SANE_OPTION_IS_SETTABLE (opt->cap) 2036141cc406Sopenharmony_ci || opt->type == SANE_TYPE_GROUP) 2037141cc406Sopenharmony_ci print_option (device, i, opt); 2038141cc406Sopenharmony_ci } 2039141cc406Sopenharmony_ci if (num_dev_options) 2040141cc406Sopenharmony_ci fputc ('\n', stdout); 2041141cc406Sopenharmony_ci} 2042141cc406Sopenharmony_ci 2043141cc406Sopenharmony_cistatic int guess_output_format(const char* output_file) 2044141cc406Sopenharmony_ci{ 2045141cc406Sopenharmony_ci if (output_file == NULL) 2046141cc406Sopenharmony_ci { 2047141cc406Sopenharmony_ci fprintf(stderr, "Output format is not set, using pnm as a default.\n"); 2048141cc406Sopenharmony_ci return OUTPUT_PNM; 2049141cc406Sopenharmony_ci } 2050141cc406Sopenharmony_ci 2051141cc406Sopenharmony_ci // if the user passes us a path with a known extension then he won't be surprised if we figure 2052141cc406Sopenharmony_ci // out correct --format option. No warning is necessary in that case. 2053141cc406Sopenharmony_ci const char* extension = strrchr(output_file, '.'); 2054141cc406Sopenharmony_ci if (extension != NULL) 2055141cc406Sopenharmony_ci { 2056141cc406Sopenharmony_ci struct { 2057141cc406Sopenharmony_ci const char* extension; 2058141cc406Sopenharmony_ci int output_format; 2059141cc406Sopenharmony_ci } formats[] = { 2060141cc406Sopenharmony_ci { ".pnm", OUTPUT_PNM }, 2061141cc406Sopenharmony_ci { ".png", OUTPUT_PNG }, 2062141cc406Sopenharmony_ci { ".jpg", OUTPUT_JPEG }, 2063141cc406Sopenharmony_ci { ".jpeg", OUTPUT_JPEG }, 2064141cc406Sopenharmony_ci { ".tiff", OUTPUT_TIFF }, 2065141cc406Sopenharmony_ci { ".tif", OUTPUT_TIFF }, 2066141cc406Sopenharmony_ci { ".pdf", OUTPUT_PDF } 2067141cc406Sopenharmony_ci }; 2068141cc406Sopenharmony_ci for (unsigned i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) 2069141cc406Sopenharmony_ci { 2070141cc406Sopenharmony_ci if (strcmp(extension, formats[i].extension) == 0) 2071141cc406Sopenharmony_ci return formats[i].output_format; 2072141cc406Sopenharmony_ci } 2073141cc406Sopenharmony_ci } 2074141cc406Sopenharmony_ci 2075141cc406Sopenharmony_ci // it would be very confusing if user makes a typo in the filename and the output format changes. 2076141cc406Sopenharmony_ci // This is most likely not what the user wanted. 2077141cc406Sopenharmony_ci fprintf(stderr, "Could not guess output format from the given path and no --format given.\n"); 2078141cc406Sopenharmony_ci exit(1); 2079141cc406Sopenharmony_ci} 2080141cc406Sopenharmony_ci 2081141cc406Sopenharmony_ciint 2082141cc406Sopenharmony_cimain (int argc, char **argv) 2083141cc406Sopenharmony_ci{ 2084141cc406Sopenharmony_ci int ch, i, index, all_options_len; 2085141cc406Sopenharmony_ci const SANE_Device **device_list; 2086141cc406Sopenharmony_ci SANE_Int num_dev_options = 0; 2087141cc406Sopenharmony_ci const char *devname = 0; 2088141cc406Sopenharmony_ci const char *defdevname = 0; 2089141cc406Sopenharmony_ci const char *format = 0; 2090141cc406Sopenharmony_ci char readbuf[2]; 2091141cc406Sopenharmony_ci char *readbuf2; 2092141cc406Sopenharmony_ci int batch = 0; 2093141cc406Sopenharmony_ci int batch_print = 0; 2094141cc406Sopenharmony_ci int batch_prompt = 0; 2095141cc406Sopenharmony_ci int batch_count = BATCH_COUNT_UNLIMITED; 2096141cc406Sopenharmony_ci int batch_start_at = 1; 2097141cc406Sopenharmony_ci int batch_increment = 1; 2098141cc406Sopenharmony_ci SANE_Status status; 2099141cc406Sopenharmony_ci char *full_optstring; 2100141cc406Sopenharmony_ci SANE_Int version_code; 2101141cc406Sopenharmony_ci void *pw = NULL; 2102141cc406Sopenharmony_ci FILE *ofp = NULL; 2103141cc406Sopenharmony_ci 2104141cc406Sopenharmony_ci buffer_size = (32 * 1024); /* default size */ 2105141cc406Sopenharmony_ci 2106141cc406Sopenharmony_ci prog_name = strrchr (argv[0], '/'); 2107141cc406Sopenharmony_ci if (prog_name) 2108141cc406Sopenharmony_ci ++prog_name; 2109141cc406Sopenharmony_ci else 2110141cc406Sopenharmony_ci prog_name = argv[0]; 2111141cc406Sopenharmony_ci 2112141cc406Sopenharmony_ci defdevname = getenv ("SANE_DEFAULT_DEVICE"); 2113141cc406Sopenharmony_ci 2114141cc406Sopenharmony_ci sane_init (&version_code, auth_callback); 2115141cc406Sopenharmony_ci 2116141cc406Sopenharmony_ci /* make a first pass through the options with error printing and argument 2117141cc406Sopenharmony_ci permutation disabled: */ 2118141cc406Sopenharmony_ci opterr = 0; 2119141cc406Sopenharmony_ci while ((ch = getopt_long (argc, argv, "-" BASE_OPTSTRING, basic_options, 2120141cc406Sopenharmony_ci &index)) != EOF) 2121141cc406Sopenharmony_ci { 2122141cc406Sopenharmony_ci switch (ch) 2123141cc406Sopenharmony_ci { 2124141cc406Sopenharmony_ci case ':': 2125141cc406Sopenharmony_ci case '?': 2126141cc406Sopenharmony_ci break; /* may be an option that we'll parse later on */ 2127141cc406Sopenharmony_ci case 'd': 2128141cc406Sopenharmony_ci devname = optarg; 2129141cc406Sopenharmony_ci break; 2130141cc406Sopenharmony_ci case 'b': 2131141cc406Sopenharmony_ci /* This may have already been set by the batch-count flag */ 2132141cc406Sopenharmony_ci batch = 1; 2133141cc406Sopenharmony_ci format = optarg; 2134141cc406Sopenharmony_ci break; 2135141cc406Sopenharmony_ci case 'h': 2136141cc406Sopenharmony_ci help = 1; 2137141cc406Sopenharmony_ci break; 2138141cc406Sopenharmony_ci case 'i': /* icc profile */ 2139141cc406Sopenharmony_ci icc_profile = optarg; 2140141cc406Sopenharmony_ci break; 2141141cc406Sopenharmony_ci case 'v': 2142141cc406Sopenharmony_ci ++verbose; 2143141cc406Sopenharmony_ci break; 2144141cc406Sopenharmony_ci case 'p': 2145141cc406Sopenharmony_ci progress = 1; 2146141cc406Sopenharmony_ci break; 2147141cc406Sopenharmony_ci case 'o': 2148141cc406Sopenharmony_ci output_file = optarg; 2149141cc406Sopenharmony_ci break; 2150141cc406Sopenharmony_ci case 'B': 2151141cc406Sopenharmony_ci if (optarg) 2152141cc406Sopenharmony_ci buffer_size = 1024 * atoi(optarg); 2153141cc406Sopenharmony_ci else 2154141cc406Sopenharmony_ci buffer_size = (1024 * 1024); 2155141cc406Sopenharmony_ci break; 2156141cc406Sopenharmony_ci case 'T': 2157141cc406Sopenharmony_ci test = 1; 2158141cc406Sopenharmony_ci break; 2159141cc406Sopenharmony_ci case 'A': 2160141cc406Sopenharmony_ci all = 1; 2161141cc406Sopenharmony_ci break; 2162141cc406Sopenharmony_ci case 'n': 2163141cc406Sopenharmony_ci dont_scan = 1; 2164141cc406Sopenharmony_ci break; 2165141cc406Sopenharmony_ci case OPTION_BATCH_PRINT: 2166141cc406Sopenharmony_ci batch_print = 1; 2167141cc406Sopenharmony_ci break; 2168141cc406Sopenharmony_ci case OPTION_BATCH_PROMPT: 2169141cc406Sopenharmony_ci batch_prompt = 1; 2170141cc406Sopenharmony_ci break; 2171141cc406Sopenharmony_ci case OPTION_BATCH_INCREMENT: 2172141cc406Sopenharmony_ci batch_increment = atoi (optarg); 2173141cc406Sopenharmony_ci break; 2174141cc406Sopenharmony_ci case OPTION_BATCH_START_AT: 2175141cc406Sopenharmony_ci batch_start_at = atoi (optarg); 2176141cc406Sopenharmony_ci break; 2177141cc406Sopenharmony_ci case OPTION_BATCH_DOUBLE: 2178141cc406Sopenharmony_ci batch_increment = 2; 2179141cc406Sopenharmony_ci break; 2180141cc406Sopenharmony_ci case OPTION_BATCH_COUNT: 2181141cc406Sopenharmony_ci batch_count = atoi (optarg); 2182141cc406Sopenharmony_ci batch = 1; 2183141cc406Sopenharmony_ci break; 2184141cc406Sopenharmony_ci case OPTION_FORMAT: 2185141cc406Sopenharmony_ci if (strcmp (optarg, "tiff") == 0) 2186141cc406Sopenharmony_ci output_format = OUTPUT_TIFF; 2187141cc406Sopenharmony_ci else if (strcmp (optarg, "png") == 0) 2188141cc406Sopenharmony_ci { 2189141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 2190141cc406Sopenharmony_ci output_format = OUTPUT_PNG; 2191141cc406Sopenharmony_ci#else 2192141cc406Sopenharmony_ci fprintf(stderr, "PNG support not compiled in\n"); 2193141cc406Sopenharmony_ci exit(1); 2194141cc406Sopenharmony_ci#endif 2195141cc406Sopenharmony_ci } 2196141cc406Sopenharmony_ci else if (strcmp (optarg, "jpeg") == 0) 2197141cc406Sopenharmony_ci { 2198141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2199141cc406Sopenharmony_ci output_format = OUTPUT_JPEG; 2200141cc406Sopenharmony_ci#else 2201141cc406Sopenharmony_ci fprintf(stderr, "JPEG support not compiled in\n"); 2202141cc406Sopenharmony_ci exit(1); 2203141cc406Sopenharmony_ci#endif 2204141cc406Sopenharmony_ci } 2205141cc406Sopenharmony_ci else if (strcmp (optarg, "pdf") == 0) 2206141cc406Sopenharmony_ci { 2207141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2208141cc406Sopenharmony_ci output_format = OUTPUT_PDF; 2209141cc406Sopenharmony_ci#else 2210141cc406Sopenharmony_ci fprintf(stderr, "PDF support not compiled in\n"); 2211141cc406Sopenharmony_ci exit(1); 2212141cc406Sopenharmony_ci#endif 2213141cc406Sopenharmony_ci } 2214141cc406Sopenharmony_ci else if (strcmp (optarg, "pnm") == 0) 2215141cc406Sopenharmony_ci { 2216141cc406Sopenharmony_ci output_format = OUTPUT_PNM; 2217141cc406Sopenharmony_ci } 2218141cc406Sopenharmony_ci else 2219141cc406Sopenharmony_ci { 2220141cc406Sopenharmony_ci fprintf(stderr, "Unknown output image format '%s'.\n", optarg); 2221141cc406Sopenharmony_ci fprintf(stderr, "Supported formats: pnm, tiff"); 2222141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 2223141cc406Sopenharmony_ci fprintf(stderr, ", png"); 2224141cc406Sopenharmony_ci#endif 2225141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2226141cc406Sopenharmony_ci fprintf(stderr, ", jpeg"); 2227141cc406Sopenharmony_ci#endif 2228141cc406Sopenharmony_ci fprintf(stderr, ".\n"); 2229141cc406Sopenharmony_ci exit(1); 2230141cc406Sopenharmony_ci } 2231141cc406Sopenharmony_ci break; 2232141cc406Sopenharmony_ci case OPTION_MD5: 2233141cc406Sopenharmony_ci accept_only_md5_auth = 1; 2234141cc406Sopenharmony_ci break; 2235141cc406Sopenharmony_ci case 'L': 2236141cc406Sopenharmony_ci case 'f': 2237141cc406Sopenharmony_ci { 2238141cc406Sopenharmony_ci int i = 0; 2239141cc406Sopenharmony_ci 2240141cc406Sopenharmony_ci status = sane_get_devices (&device_list, SANE_FALSE); 2241141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2242141cc406Sopenharmony_ci { 2243141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_get_devices() failed: %s\n", 2244141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 2245141cc406Sopenharmony_ci scanimage_exit (1); 2246141cc406Sopenharmony_ci } 2247141cc406Sopenharmony_ci 2248141cc406Sopenharmony_ci if (ch == 'L') 2249141cc406Sopenharmony_ci { 2250141cc406Sopenharmony_ci for (i = 0; device_list[i]; ++i) 2251141cc406Sopenharmony_ci { 2252141cc406Sopenharmony_ci printf ("device `%s' is a %s %s %s\n", 2253141cc406Sopenharmony_ci device_list[i]->name, device_list[i]->vendor, 2254141cc406Sopenharmony_ci device_list[i]->model, device_list[i]->type); 2255141cc406Sopenharmony_ci } 2256141cc406Sopenharmony_ci } 2257141cc406Sopenharmony_ci else 2258141cc406Sopenharmony_ci { 2259141cc406Sopenharmony_ci int i = 0, int_arg = 0; 2260141cc406Sopenharmony_ci const char *percent, *start; 2261141cc406Sopenharmony_ci const char *text_arg = 0; 2262141cc406Sopenharmony_ci char ftype; 2263141cc406Sopenharmony_ci 2264141cc406Sopenharmony_ci for (i = 0; device_list[i]; ++i) 2265141cc406Sopenharmony_ci { 2266141cc406Sopenharmony_ci start = optarg; 2267141cc406Sopenharmony_ci while (*start && (percent = strchr (start, '%'))) 2268141cc406Sopenharmony_ci { 2269141cc406Sopenharmony_ci int start_len = percent - start; 2270141cc406Sopenharmony_ci percent++; 2271141cc406Sopenharmony_ci if (*percent) 2272141cc406Sopenharmony_ci { 2273141cc406Sopenharmony_ci switch (*percent) 2274141cc406Sopenharmony_ci { 2275141cc406Sopenharmony_ci case 'd': 2276141cc406Sopenharmony_ci text_arg = device_list[i]->name; 2277141cc406Sopenharmony_ci ftype = 's'; 2278141cc406Sopenharmony_ci break; 2279141cc406Sopenharmony_ci case 'v': 2280141cc406Sopenharmony_ci text_arg = device_list[i]->vendor; 2281141cc406Sopenharmony_ci ftype = 's'; 2282141cc406Sopenharmony_ci break; 2283141cc406Sopenharmony_ci case 'm': 2284141cc406Sopenharmony_ci text_arg = device_list[i]->model; 2285141cc406Sopenharmony_ci ftype = 's'; 2286141cc406Sopenharmony_ci break; 2287141cc406Sopenharmony_ci case 't': 2288141cc406Sopenharmony_ci text_arg = device_list[i]->type; 2289141cc406Sopenharmony_ci ftype = 's'; 2290141cc406Sopenharmony_ci break; 2291141cc406Sopenharmony_ci case 'i': 2292141cc406Sopenharmony_ci int_arg = i; 2293141cc406Sopenharmony_ci ftype = 'i'; 2294141cc406Sopenharmony_ci break; 2295141cc406Sopenharmony_ci case 'n': 2296141cc406Sopenharmony_ci text_arg = "\n"; 2297141cc406Sopenharmony_ci ftype = 's'; 2298141cc406Sopenharmony_ci break; 2299141cc406Sopenharmony_ci case '%': 2300141cc406Sopenharmony_ci text_arg = "%"; 2301141cc406Sopenharmony_ci ftype = 's'; 2302141cc406Sopenharmony_ci break; 2303141cc406Sopenharmony_ci default: 2304141cc406Sopenharmony_ci fprintf (stderr, 2305141cc406Sopenharmony_ci "%s: unknown format specifier %%%c\n", 2306141cc406Sopenharmony_ci prog_name, *percent); 2307141cc406Sopenharmony_ci text_arg = "%"; 2308141cc406Sopenharmony_ci ftype = 's'; 2309141cc406Sopenharmony_ci } 2310141cc406Sopenharmony_ci printf ("%.*s", start_len, start); 2311141cc406Sopenharmony_ci switch (ftype) 2312141cc406Sopenharmony_ci { 2313141cc406Sopenharmony_ci case 's': 2314141cc406Sopenharmony_ci printf ("%s", text_arg); 2315141cc406Sopenharmony_ci break; 2316141cc406Sopenharmony_ci case 'i': 2317141cc406Sopenharmony_ci printf ("%i", int_arg); 2318141cc406Sopenharmony_ci break; 2319141cc406Sopenharmony_ci } 2320141cc406Sopenharmony_ci start = percent + 1; 2321141cc406Sopenharmony_ci } 2322141cc406Sopenharmony_ci else 2323141cc406Sopenharmony_ci { 2324141cc406Sopenharmony_ci /* last char of the string is a '%', ignore it */ 2325141cc406Sopenharmony_ci start++; 2326141cc406Sopenharmony_ci break; 2327141cc406Sopenharmony_ci } 2328141cc406Sopenharmony_ci } 2329141cc406Sopenharmony_ci if (*start) 2330141cc406Sopenharmony_ci printf ("%s", start); 2331141cc406Sopenharmony_ci } 2332141cc406Sopenharmony_ci } 2333141cc406Sopenharmony_ci if (i == 0 && ch != 'f') 2334141cc406Sopenharmony_ci printf ("\nNo scanners were identified. If you were expecting " 2335141cc406Sopenharmony_ci "something different,\ncheck that the scanner is plugged " 2336141cc406Sopenharmony_ci "in, turned on and detected by the\nsane-find-scanner tool " 2337141cc406Sopenharmony_ci "(if appropriate). Please read the documentation\nwhich came " 2338141cc406Sopenharmony_ci "with this software (README, FAQ, manpages).\n"); 2339141cc406Sopenharmony_ci 2340141cc406Sopenharmony_ci if (defdevname) 2341141cc406Sopenharmony_ci printf ("default device is `%s'\n", defdevname); 2342141cc406Sopenharmony_ci scanimage_exit (0); 2343141cc406Sopenharmony_ci break; 2344141cc406Sopenharmony_ci } 2345141cc406Sopenharmony_ci case 'V': 2346141cc406Sopenharmony_ci printf ("scanimage (%s) %s; backend version %d.%d.%d\n", PACKAGE, 2347141cc406Sopenharmony_ci VERSION, SANE_VERSION_MAJOR (version_code), 2348141cc406Sopenharmony_ci SANE_VERSION_MINOR (version_code), 2349141cc406Sopenharmony_ci SANE_VERSION_BUILD (version_code)); 2350141cc406Sopenharmony_ci scanimage_exit (0); 2351141cc406Sopenharmony_ci break; 2352141cc406Sopenharmony_ci default: 2353141cc406Sopenharmony_ci break; /* ignore device specific options for now */ 2354141cc406Sopenharmony_ci } 2355141cc406Sopenharmony_ci } 2356141cc406Sopenharmony_ci 2357141cc406Sopenharmony_ci if (help) 2358141cc406Sopenharmony_ci { 2359141cc406Sopenharmony_ci printf ("Usage: %s [OPTION]...\n\ 2360141cc406Sopenharmony_ci\n\ 2361141cc406Sopenharmony_ciStart image acquisition on a scanner device and write image data to\n\ 2362141cc406Sopenharmony_cistandard output.\n\ 2363141cc406Sopenharmony_ci\n\ 2364141cc406Sopenharmony_ciParameters are separated by a blank from single-character options (e.g.\n\ 2365141cc406Sopenharmony_ci-d epson) and by a \"=\" from multi-character options (e.g. --device-name=epson).\n\ 2366141cc406Sopenharmony_ci-d, --device-name=DEVICE use a given scanner device (e.g. hp:/dev/scanner)\n\ 2367141cc406Sopenharmony_ci --format=pnm|tiff|png|jpeg|pdf file format of output file\n\ 2368141cc406Sopenharmony_ci-i, --icc-profile=PROFILE include this ICC profile into TIFF file\n", prog_name); 2369141cc406Sopenharmony_ci printf ("\ 2370141cc406Sopenharmony_ci-L, --list-devices show available scanner devices\n\ 2371141cc406Sopenharmony_ci-f, --formatted-device-list=FORMAT similar to -L, but the FORMAT of the output\n\ 2372141cc406Sopenharmony_ci can be specified: %%d (device name), %%v (vendor),\n\ 2373141cc406Sopenharmony_ci %%m (model), %%t (type), %%i (index number), and\n\ 2374141cc406Sopenharmony_ci %%n (newline)\n\ 2375141cc406Sopenharmony_ci-b, --batch[=FORMAT] working in batch mode, FORMAT is `out%%d.pnm' `out%%d.tif'\n\ 2376141cc406Sopenharmony_ci `out%%d.png' or `out%%d.jpg' by default depending on --format\n\ 2377141cc406Sopenharmony_ci This option is incompatible with --output-file."); 2378141cc406Sopenharmony_ci printf ("\ 2379141cc406Sopenharmony_ci --batch-start=# page number to start naming files with\n\ 2380141cc406Sopenharmony_ci --batch-count=# how many pages to scan in batch mode\n\ 2381141cc406Sopenharmony_ci --batch-increment=# increase page number in filename by #\n\ 2382141cc406Sopenharmony_ci --batch-double increment page number by two, same as\n\ 2383141cc406Sopenharmony_ci --batch-increment=2\n\ 2384141cc406Sopenharmony_ci --batch-print print image filenames to stdout\n\ 2385141cc406Sopenharmony_ci --batch-prompt ask for pressing a key before scanning a page\n"); 2386141cc406Sopenharmony_ci printf ("\ 2387141cc406Sopenharmony_ci --accept-md5-only only accept authorization requests using md5\n\ 2388141cc406Sopenharmony_ci-p, --progress print progress messages\n\ 2389141cc406Sopenharmony_ci-o, --output-file=PATH save output to the given file instead of stdout.\n\ 2390141cc406Sopenharmony_ci This option is incompatible with --batch.\n\ 2391141cc406Sopenharmony_ci-n, --dont-scan only set options, don't actually scan\n\ 2392141cc406Sopenharmony_ci-T, --test test backend thoroughly\n\ 2393141cc406Sopenharmony_ci-A, --all-options list all available backend options\n\ 2394141cc406Sopenharmony_ci-h, --help display this help message and exit\n\ 2395141cc406Sopenharmony_ci-v, --verbose give even more status messages\n\ 2396141cc406Sopenharmony_ci-B, --buffer-size=# change input buffer size (in kB, default 32)\n"); 2397141cc406Sopenharmony_ci printf ("\ 2398141cc406Sopenharmony_ci-V, --version print version information\n"); 2399141cc406Sopenharmony_ci } 2400141cc406Sopenharmony_ci 2401141cc406Sopenharmony_ci if (batch && output_file != NULL) 2402141cc406Sopenharmony_ci { 2403141cc406Sopenharmony_ci fprintf(stderr, "--batch and --output-file can't be used together.\n"); 2404141cc406Sopenharmony_ci exit(1); 2405141cc406Sopenharmony_ci } 2406141cc406Sopenharmony_ci 2407141cc406Sopenharmony_ci if (output_format == OUTPUT_UNKNOWN) 2408141cc406Sopenharmony_ci output_format = guess_output_format(output_file); 2409141cc406Sopenharmony_ci 2410141cc406Sopenharmony_ci if (!devname) 2411141cc406Sopenharmony_ci { 2412141cc406Sopenharmony_ci /* If no device name was specified explicitly, we look at the 2413141cc406Sopenharmony_ci environment variable SANE_DEFAULT_DEVICE. If this variable 2414141cc406Sopenharmony_ci is not set, we open the first device we find (if any): */ 2415141cc406Sopenharmony_ci devname = defdevname; 2416141cc406Sopenharmony_ci if (!devname) 2417141cc406Sopenharmony_ci { 2418141cc406Sopenharmony_ci status = sane_get_devices (&device_list, SANE_FALSE); 2419141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2420141cc406Sopenharmony_ci { 2421141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_get_devices() failed: %s\n", 2422141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 2423141cc406Sopenharmony_ci scanimage_exit (1); 2424141cc406Sopenharmony_ci } 2425141cc406Sopenharmony_ci if (!device_list[0]) 2426141cc406Sopenharmony_ci { 2427141cc406Sopenharmony_ci fprintf (stderr, "%s: no SANE devices found\n", prog_name); 2428141cc406Sopenharmony_ci scanimage_exit (1); 2429141cc406Sopenharmony_ci } 2430141cc406Sopenharmony_ci devname = device_list[0]->name; 2431141cc406Sopenharmony_ci } 2432141cc406Sopenharmony_ci } 2433141cc406Sopenharmony_ci 2434141cc406Sopenharmony_ci status = sane_open (devname, &device); 2435141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2436141cc406Sopenharmony_ci { 2437141cc406Sopenharmony_ci fprintf (stderr, "%s: open of device %s failed: %s\n", 2438141cc406Sopenharmony_ci prog_name, devname, sane_strstatus (status)); 2439141cc406Sopenharmony_ci if (devname[0] == '/') 2440141cc406Sopenharmony_ci fprintf (stderr, "\nYou seem to have specified a UNIX device name, " 2441141cc406Sopenharmony_ci "or filename instead of selecting\nthe SANE scanner or " 2442141cc406Sopenharmony_ci "image acquisition device you want to use. As an example,\n" 2443141cc406Sopenharmony_ci "you might want \"epson:/dev/sg0\" or " 2444141cc406Sopenharmony_ci "\"hp:/dev/usbscanner0\". If any supported\ndevices are " 2445141cc406Sopenharmony_ci "installed in your system, you should be able to see a " 2446141cc406Sopenharmony_ci "list with\n\"scanimage --list-devices\".\n"); 2447141cc406Sopenharmony_ci if (help) 2448141cc406Sopenharmony_ci device = 0; 2449141cc406Sopenharmony_ci else 2450141cc406Sopenharmony_ci scanimage_exit (1); 2451141cc406Sopenharmony_ci } 2452141cc406Sopenharmony_ci 2453141cc406Sopenharmony_ci if (device) 2454141cc406Sopenharmony_ci { 2455141cc406Sopenharmony_ci const SANE_Option_Descriptor * desc_ptr; 2456141cc406Sopenharmony_ci 2457141cc406Sopenharmony_ci /* Good form to always get the descriptor once before value */ 2458141cc406Sopenharmony_ci desc_ptr = sane_get_option_descriptor(device, 0); 2459141cc406Sopenharmony_ci if (!desc_ptr) 2460141cc406Sopenharmony_ci { 2461141cc406Sopenharmony_ci fprintf (stderr, "%s: unable to get option count descriptor\n", 2462141cc406Sopenharmony_ci prog_name); 2463141cc406Sopenharmony_ci scanimage_exit (1); 2464141cc406Sopenharmony_ci } 2465141cc406Sopenharmony_ci 2466141cc406Sopenharmony_ci /* We got a device, find out how many options it has */ 2467141cc406Sopenharmony_ci status = sane_control_option (device, 0, SANE_ACTION_GET_VALUE, 2468141cc406Sopenharmony_ci &num_dev_options, 0); 2469141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2470141cc406Sopenharmony_ci { 2471141cc406Sopenharmony_ci fprintf (stderr, "%s: unable to determine option count\n", 2472141cc406Sopenharmony_ci prog_name); 2473141cc406Sopenharmony_ci scanimage_exit (1); 2474141cc406Sopenharmony_ci } 2475141cc406Sopenharmony_ci 2476141cc406Sopenharmony_ci /* malloc global option lists */ 2477141cc406Sopenharmony_ci all_options_len = num_dev_options + NELEMS (basic_options) + 1; 2478141cc406Sopenharmony_ci all_options = malloc (all_options_len * sizeof (all_options[0])); 2479141cc406Sopenharmony_ci option_number_len = num_dev_options; 2480141cc406Sopenharmony_ci option_number = malloc (option_number_len * sizeof (option_number[0])); 2481141cc406Sopenharmony_ci if (!all_options || !option_number) 2482141cc406Sopenharmony_ci { 2483141cc406Sopenharmony_ci fprintf (stderr, "%s: out of memory in main()\n", 2484141cc406Sopenharmony_ci prog_name); 2485141cc406Sopenharmony_ci scanimage_exit (1); 2486141cc406Sopenharmony_ci } 2487141cc406Sopenharmony_ci 2488141cc406Sopenharmony_ci /* load global option lists */ 2489141cc406Sopenharmony_ci fetch_options (device); 2490141cc406Sopenharmony_ci 2491141cc406Sopenharmony_ci { 2492141cc406Sopenharmony_ci char *larg, *targ, *xarg, *yarg; 2493141cc406Sopenharmony_ci larg = targ = xarg = yarg = ""; 2494141cc406Sopenharmony_ci 2495141cc406Sopenharmony_ci /* Maybe accept t, l, x, and y options. */ 2496141cc406Sopenharmony_ci if (window[0]) 2497141cc406Sopenharmony_ci xarg = "x:"; 2498141cc406Sopenharmony_ci 2499141cc406Sopenharmony_ci if (window[1]) 2500141cc406Sopenharmony_ci yarg = "y:"; 2501141cc406Sopenharmony_ci 2502141cc406Sopenharmony_ci if (window[2]) 2503141cc406Sopenharmony_ci larg = "l:"; 2504141cc406Sopenharmony_ci 2505141cc406Sopenharmony_ci if (window[3]) 2506141cc406Sopenharmony_ci targ = "t:"; 2507141cc406Sopenharmony_ci 2508141cc406Sopenharmony_ci /* Now allocate the full option list. */ 2509141cc406Sopenharmony_ci full_optstring = malloc (strlen (BASE_OPTSTRING) 2510141cc406Sopenharmony_ci + strlen (larg) + strlen (targ) 2511141cc406Sopenharmony_ci + strlen (xarg) + strlen (yarg) + 1); 2512141cc406Sopenharmony_ci 2513141cc406Sopenharmony_ci if (!full_optstring) 2514141cc406Sopenharmony_ci { 2515141cc406Sopenharmony_ci fprintf (stderr, "%s: out of memory\n", prog_name); 2516141cc406Sopenharmony_ci scanimage_exit (1); 2517141cc406Sopenharmony_ci } 2518141cc406Sopenharmony_ci 2519141cc406Sopenharmony_ci strcpy (full_optstring, BASE_OPTSTRING); 2520141cc406Sopenharmony_ci strcat (full_optstring, larg); 2521141cc406Sopenharmony_ci strcat (full_optstring, targ); 2522141cc406Sopenharmony_ci strcat (full_optstring, xarg); 2523141cc406Sopenharmony_ci strcat (full_optstring, yarg); 2524141cc406Sopenharmony_ci } 2525141cc406Sopenharmony_ci 2526141cc406Sopenharmony_ci /* re-run argument processing with backend-specific options included 2527141cc406Sopenharmony_ci * this time, enable error printing and arg permutation */ 2528141cc406Sopenharmony_ci optind = 0; 2529141cc406Sopenharmony_ci opterr = 1; 2530141cc406Sopenharmony_ci while ((ch = getopt_long (argc, argv, full_optstring, all_options, 2531141cc406Sopenharmony_ci &index)) != EOF) 2532141cc406Sopenharmony_ci { 2533141cc406Sopenharmony_ci switch (ch) 2534141cc406Sopenharmony_ci { 2535141cc406Sopenharmony_ci case ':': 2536141cc406Sopenharmony_ci case '?': 2537141cc406Sopenharmony_ci scanimage_exit (1); /* error message is printed by getopt_long() */ 2538141cc406Sopenharmony_ci 2539141cc406Sopenharmony_ci case 'd': 2540141cc406Sopenharmony_ci case 'h': 2541141cc406Sopenharmony_ci case 'p': 2542141cc406Sopenharmony_ci case 'o': 2543141cc406Sopenharmony_ci case 'v': 2544141cc406Sopenharmony_ci case 'V': 2545141cc406Sopenharmony_ci case 'T': 2546141cc406Sopenharmony_ci case 'B': 2547141cc406Sopenharmony_ci /* previously handled options */ 2548141cc406Sopenharmony_ci break; 2549141cc406Sopenharmony_ci 2550141cc406Sopenharmony_ci case 'x': 2551141cc406Sopenharmony_ci window_val_user[0] = 1; 2552141cc406Sopenharmony_ci parse_vector (&window_option[0], optarg, &window_val[0], 1); 2553141cc406Sopenharmony_ci break; 2554141cc406Sopenharmony_ci 2555141cc406Sopenharmony_ci case 'y': 2556141cc406Sopenharmony_ci window_val_user[1] = 1; 2557141cc406Sopenharmony_ci parse_vector (&window_option[1], optarg, &window_val[1], 1); 2558141cc406Sopenharmony_ci break; 2559141cc406Sopenharmony_ci 2560141cc406Sopenharmony_ci case 'l': /* tl-x */ 2561141cc406Sopenharmony_ci process_backend_option (device, window[2], optarg); 2562141cc406Sopenharmony_ci break; 2563141cc406Sopenharmony_ci 2564141cc406Sopenharmony_ci case 't': /* tl-y */ 2565141cc406Sopenharmony_ci process_backend_option (device, window[3], optarg); 2566141cc406Sopenharmony_ci break; 2567141cc406Sopenharmony_ci 2568141cc406Sopenharmony_ci case 0: 2569141cc406Sopenharmony_ci process_backend_option (device, option_number[index], optarg); 2570141cc406Sopenharmony_ci break; 2571141cc406Sopenharmony_ci } 2572141cc406Sopenharmony_ci } 2573141cc406Sopenharmony_ci if (optind < argc) 2574141cc406Sopenharmony_ci { 2575141cc406Sopenharmony_ci fprintf (stderr, "%s: argument without option: `%s'; ", prog_name, 2576141cc406Sopenharmony_ci argv[argc - 1]); 2577141cc406Sopenharmony_ci fprintf (stderr, "try %s --help\n", prog_name); 2578141cc406Sopenharmony_ci scanimage_exit (1); 2579141cc406Sopenharmony_ci } 2580141cc406Sopenharmony_ci 2581141cc406Sopenharmony_ci free (full_optstring); 2582141cc406Sopenharmony_ci 2583141cc406Sopenharmony_ci /* convert x/y to br_x/br_y */ 2584141cc406Sopenharmony_ci for (index = 0; index < 2; ++index) 2585141cc406Sopenharmony_ci if (window[index]) 2586141cc406Sopenharmony_ci { 2587141cc406Sopenharmony_ci SANE_Word pos = 0; 2588141cc406Sopenharmony_ci SANE_Word val = window_val[index]; 2589141cc406Sopenharmony_ci 2590141cc406Sopenharmony_ci if (window[index + 2]) 2591141cc406Sopenharmony_ci { 2592141cc406Sopenharmony_ci sane_control_option (device, window[index + 2], 2593141cc406Sopenharmony_ci SANE_ACTION_GET_VALUE, &pos, 0); 2594141cc406Sopenharmony_ci val += pos; 2595141cc406Sopenharmony_ci } 2596141cc406Sopenharmony_ci set_option (device, window[index], &val); 2597141cc406Sopenharmony_ci } 2598141cc406Sopenharmony_ci 2599141cc406Sopenharmony_ci /* output device-specific help */ 2600141cc406Sopenharmony_ci if (help) 2601141cc406Sopenharmony_ci { 2602141cc406Sopenharmony_ci printf ("\nOptions specific to device `%s':\n", devname); 2603141cc406Sopenharmony_ci print_options(device, num_dev_options, SANE_FALSE); 2604141cc406Sopenharmony_ci } 2605141cc406Sopenharmony_ci 2606141cc406Sopenharmony_ci /* list all device-specific options */ 2607141cc406Sopenharmony_ci if (all) 2608141cc406Sopenharmony_ci { 2609141cc406Sopenharmony_ci printf ("\nAll options specific to device `%s':\n", devname); 2610141cc406Sopenharmony_ci print_options(device, num_dev_options, SANE_TRUE); 2611141cc406Sopenharmony_ci scanimage_exit (0); 2612141cc406Sopenharmony_ci } 2613141cc406Sopenharmony_ci } 2614141cc406Sopenharmony_ci 2615141cc406Sopenharmony_ci /* output device list */ 2616141cc406Sopenharmony_ci if (help) 2617141cc406Sopenharmony_ci { 2618141cc406Sopenharmony_ci printf ("\ 2619141cc406Sopenharmony_ciType ``%s --help -d DEVICE'' to get list of all options for DEVICE.\n\ 2620141cc406Sopenharmony_ci\n\ 2621141cc406Sopenharmony_ciList of available devices:", prog_name); 2622141cc406Sopenharmony_ci status = sane_get_devices (&device_list, SANE_FALSE); 2623141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 2624141cc406Sopenharmony_ci { 2625141cc406Sopenharmony_ci int column = 80; 2626141cc406Sopenharmony_ci 2627141cc406Sopenharmony_ci for (i = 0; device_list[i]; ++i) 2628141cc406Sopenharmony_ci { 2629141cc406Sopenharmony_ci if (column + strlen (device_list[i]->name) + 1 >= 80) 2630141cc406Sopenharmony_ci { 2631141cc406Sopenharmony_ci printf ("\n "); 2632141cc406Sopenharmony_ci column = 4; 2633141cc406Sopenharmony_ci } 2634141cc406Sopenharmony_ci if (column > 4) 2635141cc406Sopenharmony_ci { 2636141cc406Sopenharmony_ci fputc (' ', stdout); 2637141cc406Sopenharmony_ci column += 1; 2638141cc406Sopenharmony_ci } 2639141cc406Sopenharmony_ci fputs (device_list[i]->name, stdout); 2640141cc406Sopenharmony_ci column += strlen (device_list[i]->name); 2641141cc406Sopenharmony_ci } 2642141cc406Sopenharmony_ci } 2643141cc406Sopenharmony_ci fputc ('\n', stdout); 2644141cc406Sopenharmony_ci scanimage_exit (0); 2645141cc406Sopenharmony_ci } 2646141cc406Sopenharmony_ci 2647141cc406Sopenharmony_ci if (dont_scan) 2648141cc406Sopenharmony_ci scanimage_exit (0); 2649141cc406Sopenharmony_ci 2650141cc406Sopenharmony_ci if (output_format != OUTPUT_PNM) 2651141cc406Sopenharmony_ci resolution_value = get_resolution (); 2652141cc406Sopenharmony_ci 2653141cc406Sopenharmony_ci#ifdef SIGHUP 2654141cc406Sopenharmony_ci signal (SIGHUP, sighandler); 2655141cc406Sopenharmony_ci#endif 2656141cc406Sopenharmony_ci#ifdef SIGPIPE 2657141cc406Sopenharmony_ci signal (SIGPIPE, sighandler); 2658141cc406Sopenharmony_ci#endif 2659141cc406Sopenharmony_ci signal (SIGINT, sighandler); 2660141cc406Sopenharmony_ci signal (SIGTERM, sighandler); 2661141cc406Sopenharmony_ci 2662141cc406Sopenharmony_ci if (test == 0) 2663141cc406Sopenharmony_ci { 2664141cc406Sopenharmony_ci int n = batch_start_at; 2665141cc406Sopenharmony_ci 2666141cc406Sopenharmony_ci if (batch && NULL == format) 2667141cc406Sopenharmony_ci { 2668141cc406Sopenharmony_ci switch(output_format) { 2669141cc406Sopenharmony_ci case OUTPUT_TIFF: 2670141cc406Sopenharmony_ci format = "out%d.tif"; 2671141cc406Sopenharmony_ci break; 2672141cc406Sopenharmony_ci case OUTPUT_PNM: 2673141cc406Sopenharmony_ci format = "out%d.pnm"; 2674141cc406Sopenharmony_ci break; 2675141cc406Sopenharmony_ci#ifdef HAVE_LIBPNG 2676141cc406Sopenharmony_ci case OUTPUT_PNG: 2677141cc406Sopenharmony_ci format = "out%d.png"; 2678141cc406Sopenharmony_ci break; 2679141cc406Sopenharmony_ci#endif 2680141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2681141cc406Sopenharmony_ci case OUTPUT_PDF: 2682141cc406Sopenharmony_ci format = "out%d.pdf"; 2683141cc406Sopenharmony_ci break; 2684141cc406Sopenharmony_ci case OUTPUT_JPEG: 2685141cc406Sopenharmony_ci format = "out%d.jpg"; 2686141cc406Sopenharmony_ci break; 2687141cc406Sopenharmony_ci#endif 2688141cc406Sopenharmony_ci } 2689141cc406Sopenharmony_ci } 2690141cc406Sopenharmony_ci 2691141cc406Sopenharmony_ci if (!batch) 2692141cc406Sopenharmony_ci { 2693141cc406Sopenharmony_ci ofp = stdout; 2694141cc406Sopenharmony_ci if (output_file != NULL) 2695141cc406Sopenharmony_ci { 2696141cc406Sopenharmony_ci ofp = fopen(output_file, "w"); 2697141cc406Sopenharmony_ci if (ofp == NULL) 2698141cc406Sopenharmony_ci { 2699141cc406Sopenharmony_ci fprintf(stderr, "%s: could not open output file '%s', " 2700141cc406Sopenharmony_ci "exiting\n", prog_name, output_file); 2701141cc406Sopenharmony_ci scanimage_exit(1); 2702141cc406Sopenharmony_ci } 2703141cc406Sopenharmony_ci } 2704141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2705141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2706141cc406Sopenharmony_ci { 2707141cc406Sopenharmony_ci sane_pdf_open(&pw, ofp ); 2708141cc406Sopenharmony_ci sane_pdf_start_doc( pw ); 2709141cc406Sopenharmony_ci } 2710141cc406Sopenharmony_ci#endif 2711141cc406Sopenharmony_ci } 2712141cc406Sopenharmony_ci 2713141cc406Sopenharmony_ci if (batch) 2714141cc406Sopenharmony_ci { 2715141cc406Sopenharmony_ci fputs("Scanning ", stderr); 2716141cc406Sopenharmony_ci if (batch_count == BATCH_COUNT_UNLIMITED) 2717141cc406Sopenharmony_ci fputs("infinity", stderr); 2718141cc406Sopenharmony_ci else 2719141cc406Sopenharmony_ci fprintf(stderr, "%d", batch_count); 2720141cc406Sopenharmony_ci fprintf (stderr, 2721141cc406Sopenharmony_ci " page%s, incrementing by %d, numbering from %d\n", 2722141cc406Sopenharmony_ci batch_count == 1 ? "" : "s", batch_increment, batch_start_at); 2723141cc406Sopenharmony_ci } 2724141cc406Sopenharmony_ci 2725141cc406Sopenharmony_ci else if(isatty(fileno(ofp))){ 2726141cc406Sopenharmony_ci fprintf (stderr,"%s: output is not a file, exiting\n", prog_name); 2727141cc406Sopenharmony_ci scanimage_exit (1); 2728141cc406Sopenharmony_ci } 2729141cc406Sopenharmony_ci 2730141cc406Sopenharmony_ci buffer = malloc (buffer_size); 2731141cc406Sopenharmony_ci 2732141cc406Sopenharmony_ci do 2733141cc406Sopenharmony_ci { 2734141cc406Sopenharmony_ci char path[PATH_MAX]; 2735141cc406Sopenharmony_ci char part_path[PATH_MAX]; 2736141cc406Sopenharmony_ci if (batch) /* format is NULL unless batch mode */ 2737141cc406Sopenharmony_ci { 2738141cc406Sopenharmony_ci sprintf (path, format, n); /* love --(C++) */ 2739141cc406Sopenharmony_ci strcpy (part_path, path); 2740141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2741141cc406Sopenharmony_ci if (output_format != OUTPUT_PDF) 2742141cc406Sopenharmony_ci#endif 2743141cc406Sopenharmony_ci strcat (part_path, ".part"); 2744141cc406Sopenharmony_ci } 2745141cc406Sopenharmony_ci 2746141cc406Sopenharmony_ci 2747141cc406Sopenharmony_ci if (batch) 2748141cc406Sopenharmony_ci { 2749141cc406Sopenharmony_ci if (batch_prompt) 2750141cc406Sopenharmony_ci { 2751141cc406Sopenharmony_ci fprintf (stderr, "Place document no. %d on the scanner.\n", 2752141cc406Sopenharmony_ci n); 2753141cc406Sopenharmony_ci fprintf (stderr, "Press <RETURN> to continue.\n"); 2754141cc406Sopenharmony_ci fprintf (stderr, "Press Ctrl + D to terminate.\n"); 2755141cc406Sopenharmony_ci readbuf2 = fgets (readbuf, 2, stdin); 2756141cc406Sopenharmony_ci 2757141cc406Sopenharmony_ci if (readbuf2 == NULL) 2758141cc406Sopenharmony_ci { 2759141cc406Sopenharmony_ci if (ofp) 2760141cc406Sopenharmony_ci { 2761141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2762141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2763141cc406Sopenharmony_ci { 2764141cc406Sopenharmony_ci sane_pdf_end_doc( pw ); 2765141cc406Sopenharmony_ci sane_pdf_close ( pw ); 2766141cc406Sopenharmony_ci } 2767141cc406Sopenharmony_ci#endif 2768141cc406Sopenharmony_ci fclose (ofp); 2769141cc406Sopenharmony_ci ofp = NULL; 2770141cc406Sopenharmony_ci } 2771141cc406Sopenharmony_ci break; /* get out of this loop */ 2772141cc406Sopenharmony_ci } 2773141cc406Sopenharmony_ci } 2774141cc406Sopenharmony_ci fprintf (stderr, "Scanning page %d\n", n); 2775141cc406Sopenharmony_ci } 2776141cc406Sopenharmony_ci 2777141cc406Sopenharmony_ci#ifdef SANE_STATUS_WARMING_UP 2778141cc406Sopenharmony_ci do 2779141cc406Sopenharmony_ci { 2780141cc406Sopenharmony_ci status = sane_start (device); 2781141cc406Sopenharmony_ci } 2782141cc406Sopenharmony_ci while(status == SANE_STATUS_WARMING_UP); 2783141cc406Sopenharmony_ci#else 2784141cc406Sopenharmony_ci status = sane_start (device); 2785141cc406Sopenharmony_ci#endif 2786141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 2787141cc406Sopenharmony_ci { 2788141cc406Sopenharmony_ci fprintf (stderr, "%s: sane_start: %s\n", 2789141cc406Sopenharmony_ci prog_name, sane_strstatus (status)); 2790141cc406Sopenharmony_ci if (ofp ) 2791141cc406Sopenharmony_ci { 2792141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2793141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2794141cc406Sopenharmony_ci { 2795141cc406Sopenharmony_ci sane_pdf_end_doc( pw ); 2796141cc406Sopenharmony_ci sane_pdf_close ( pw ); 2797141cc406Sopenharmony_ci } 2798141cc406Sopenharmony_ci#endif 2799141cc406Sopenharmony_ci fclose (ofp); 2800141cc406Sopenharmony_ci ofp = NULL; 2801141cc406Sopenharmony_ci } 2802141cc406Sopenharmony_ci break; 2803141cc406Sopenharmony_ci } 2804141cc406Sopenharmony_ci 2805141cc406Sopenharmony_ci 2806141cc406Sopenharmony_ci /* write to .part file while scanning is in progress */ 2807141cc406Sopenharmony_ci if (batch) 2808141cc406Sopenharmony_ci { 2809141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2810141cc406Sopenharmony_ci SANE_Bool init_pdf = SANE_FALSE; 2811141cc406Sopenharmony_ci#endif 2812141cc406Sopenharmony_ci if (ofp == NULL) 2813141cc406Sopenharmony_ci { 2814141cc406Sopenharmony_ci ofp = fopen (part_path, "w"); 2815141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2816141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF && ofp != NULL) 2817141cc406Sopenharmony_ci init_pdf = SANE_TRUE; 2818141cc406Sopenharmony_ci#endif 2819141cc406Sopenharmony_ci } 2820141cc406Sopenharmony_ci if (NULL == ofp) 2821141cc406Sopenharmony_ci { 2822141cc406Sopenharmony_ci fprintf (stderr, "cannot open %s\n", part_path); 2823141cc406Sopenharmony_ci sane_cancel (device); 2824141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 2825141cc406Sopenharmony_ci } 2826141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2827141cc406Sopenharmony_ci if (init_pdf ) 2828141cc406Sopenharmony_ci { 2829141cc406Sopenharmony_ci sane_pdf_open( &pw, ofp ); 2830141cc406Sopenharmony_ci sane_pdf_start_doc ( pw ); 2831141cc406Sopenharmony_ci } 2832141cc406Sopenharmony_ci#endif 2833141cc406Sopenharmony_ci } 2834141cc406Sopenharmony_ci 2835141cc406Sopenharmony_ci status = scan_it (ofp, pw); 2836141cc406Sopenharmony_ci 2837141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2838141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2839141cc406Sopenharmony_ci { 2840141cc406Sopenharmony_ci sane_pdf_end_page( pw ); 2841141cc406Sopenharmony_ci fflush( ofp ); 2842141cc406Sopenharmony_ci } 2843141cc406Sopenharmony_ci#endif 2844141cc406Sopenharmony_ci 2845141cc406Sopenharmony_ci if (batch) 2846141cc406Sopenharmony_ci { 2847141cc406Sopenharmony_ci fprintf (stderr, "Scanned page %d.", n); 2848141cc406Sopenharmony_ci fprintf (stderr, " (scanner status = %d)\n", status); 2849141cc406Sopenharmony_ci } 2850141cc406Sopenharmony_ci 2851141cc406Sopenharmony_ci switch (status) 2852141cc406Sopenharmony_ci { 2853141cc406Sopenharmony_ci case SANE_STATUS_GOOD: 2854141cc406Sopenharmony_ci case SANE_STATUS_EOF: 2855141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 2856141cc406Sopenharmony_ci if (batch) 2857141cc406Sopenharmony_ci { 2858141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2859141cc406Sopenharmony_ci if (output_format != OUTPUT_PDF) 2860141cc406Sopenharmony_ci { 2861141cc406Sopenharmony_ci#endif 2862141cc406Sopenharmony_ci if (!ofp || 0 != fclose(ofp)) 2863141cc406Sopenharmony_ci { 2864141cc406Sopenharmony_ci fprintf (stderr, "cannot close image file\n"); 2865141cc406Sopenharmony_ci sane_cancel (device); 2866141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 2867141cc406Sopenharmony_ci } 2868141cc406Sopenharmony_ci else 2869141cc406Sopenharmony_ci { 2870141cc406Sopenharmony_ci ofp = NULL; 2871141cc406Sopenharmony_ci /* let the fully scanned file show up */ 2872141cc406Sopenharmony_ci if (rename (part_path, path)) 2873141cc406Sopenharmony_ci { 2874141cc406Sopenharmony_ci fprintf (stderr, "cannot rename %s to %s\n", 2875141cc406Sopenharmony_ci part_path, path); 2876141cc406Sopenharmony_ci sane_cancel (device); 2877141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 2878141cc406Sopenharmony_ci } 2879141cc406Sopenharmony_ci if (batch_print) 2880141cc406Sopenharmony_ci { 2881141cc406Sopenharmony_ci fprintf (stdout, "%s\n", path); 2882141cc406Sopenharmony_ci fflush (stdout); 2883141cc406Sopenharmony_ci } 2884141cc406Sopenharmony_ci } 2885141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2886141cc406Sopenharmony_ci } 2887141cc406Sopenharmony_ci#endif 2888141cc406Sopenharmony_ci } 2889141cc406Sopenharmony_ci else 2890141cc406Sopenharmony_ci { 2891141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2892141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2893141cc406Sopenharmony_ci { 2894141cc406Sopenharmony_ci sane_pdf_end_doc( pw ); 2895141cc406Sopenharmony_ci fflush( ofp ); 2896141cc406Sopenharmony_ci sane_pdf_close ( pw ); 2897141cc406Sopenharmony_ci } 2898141cc406Sopenharmony_ci#endif 2899141cc406Sopenharmony_ci if (output_file && ofp) 2900141cc406Sopenharmony_ci { 2901141cc406Sopenharmony_ci fclose(ofp); 2902141cc406Sopenharmony_ci ofp = NULL; 2903141cc406Sopenharmony_ci } 2904141cc406Sopenharmony_ci } 2905141cc406Sopenharmony_ci break; 2906141cc406Sopenharmony_ci default: 2907141cc406Sopenharmony_ci if (batch) 2908141cc406Sopenharmony_ci { 2909141cc406Sopenharmony_ci if (ofp) 2910141cc406Sopenharmony_ci { 2911141cc406Sopenharmony_ci fclose (ofp); 2912141cc406Sopenharmony_ci ofp = NULL; 2913141cc406Sopenharmony_ci } 2914141cc406Sopenharmony_ci unlink (part_path); 2915141cc406Sopenharmony_ci } 2916141cc406Sopenharmony_ci else 2917141cc406Sopenharmony_ci { 2918141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2919141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2920141cc406Sopenharmony_ci { 2921141cc406Sopenharmony_ci sane_pdf_end_doc( pw ); 2922141cc406Sopenharmony_ci sane_pdf_close ( pw ); 2923141cc406Sopenharmony_ci } 2924141cc406Sopenharmony_ci#endif 2925141cc406Sopenharmony_ci if (output_file && ofp) 2926141cc406Sopenharmony_ci { 2927141cc406Sopenharmony_ci fclose(ofp); 2928141cc406Sopenharmony_ci ofp = NULL; 2929141cc406Sopenharmony_ci } 2930141cc406Sopenharmony_ci unlink (output_file); 2931141cc406Sopenharmony_ci } 2932141cc406Sopenharmony_ci break; 2933141cc406Sopenharmony_ci } /* switch */ 2934141cc406Sopenharmony_ci n += batch_increment; 2935141cc406Sopenharmony_ci } 2936141cc406Sopenharmony_ci while ((batch 2937141cc406Sopenharmony_ci && (batch_count == BATCH_COUNT_UNLIMITED || --batch_count)) 2938141cc406Sopenharmony_ci && SANE_STATUS_GOOD == status); 2939141cc406Sopenharmony_ci 2940141cc406Sopenharmony_ci if (batch) 2941141cc406Sopenharmony_ci { 2942141cc406Sopenharmony_ci#ifdef HAVE_LIBJPEG 2943141cc406Sopenharmony_ci if (output_format == OUTPUT_PDF) 2944141cc406Sopenharmony_ci { 2945141cc406Sopenharmony_ci if (output_file && ofp) 2946141cc406Sopenharmony_ci { 2947141cc406Sopenharmony_ci sane_pdf_end_doc( pw ); 2948141cc406Sopenharmony_ci fflush( ofp ); 2949141cc406Sopenharmony_ci sane_pdf_close ( pw ); 2950141cc406Sopenharmony_ci fclose(ofp); 2951141cc406Sopenharmony_ci ofp = NULL; 2952141cc406Sopenharmony_ci } 2953141cc406Sopenharmony_ci } 2954141cc406Sopenharmony_ci#endif 2955141cc406Sopenharmony_ci int num_pgs = (n - batch_start_at) / batch_increment; 2956141cc406Sopenharmony_ci fprintf (stderr, "Batch terminated, %d page%s scanned\n", 2957141cc406Sopenharmony_ci num_pgs, num_pgs == 1 ? "" : "s"); 2958141cc406Sopenharmony_ci } 2959141cc406Sopenharmony_ci 2960141cc406Sopenharmony_ci if (batch 2961141cc406Sopenharmony_ci && SANE_STATUS_NO_DOCS == status 2962141cc406Sopenharmony_ci && (batch_count == BATCH_COUNT_UNLIMITED) 2963141cc406Sopenharmony_ci && n > batch_start_at) 2964141cc406Sopenharmony_ci status = SANE_STATUS_GOOD; 2965141cc406Sopenharmony_ci 2966141cc406Sopenharmony_ci sane_cancel (device); 2967141cc406Sopenharmony_ci } 2968141cc406Sopenharmony_ci else 2969141cc406Sopenharmony_ci status = test_it (); 2970141cc406Sopenharmony_ci 2971141cc406Sopenharmony_ci scanimage_exit (status); 2972141cc406Sopenharmony_ci /* the line below avoids compiler warnings */ 2973141cc406Sopenharmony_ci return status; 2974141cc406Sopenharmony_ci} 2975