/* Copyright (C) 2008, Panasonic Russia Ltd. */ /* sane - Scanner Access Now Easy. Panasonic KV-S1020C / KV-S1025C USB scanners. */ #define DEBUG_DECLARE_ONLY #include "../include/sane/config.h" #include #include #include #include #include #include #include #include #include #include #include "../include/sane/sane.h" #include "../include/sane/saneopts.h" #include "../include/sane/sanei.h" #include "../include/sane/sanei_usb.h" #include "../include/sane/sanei_backend.h" #include "../include/sane/sanei_config.h" #include "../include/lassert.h" #include "kvs1025.h" #include "kvs1025_low.h" #include "../include/sane/sanei_debug.h" /* Option lists */ static SANE_String_Const go_scan_mode_list[] = { SANE_I18N ("bw"), SANE_I18N ("halftone"), SANE_I18N ("gray"), SANE_I18N ("color"), NULL }; /* static int go_scan_mode_val[] = { 0x00, 0x01, 0x02, 0x05 };*/ static const SANE_Word go_resolutions_list[] = { 11, /* list size */ 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600 }; /* List of scan sources */ static SANE_String_Const go_scan_source_list[] = { SANE_I18N ("adf"), SANE_I18N ("fb"), NULL }; static const int go_scan_source_val[] = { 0, 0x1 }; /* List of feeder modes */ static SANE_String_Const go_feeder_mode_list[] = { SANE_I18N ("single"), SANE_I18N ("continuous"), NULL }; static const int go_feeder_mode_val[] = { 0x00, 0xff }; /* List of manual feed mode */ static SANE_String_Const go_manual_feed_list[] = { SANE_I18N ("off"), SANE_I18N ("wait_doc"), SANE_I18N ("wait_key"), NULL }; static const int go_manual_feed_val[] = { 0x00, 0x01, 0x02 }; /* List of paper sizes */ static SANE_String_Const go_paper_list[] = { SANE_I18N ("user_def"), SANE_I18N ("business_card"), SANE_I18N ("Check"), /*SANE_I18N ("A3"), */ SANE_I18N ("A4"), SANE_I18N ("A5"), SANE_I18N ("A6"), SANE_I18N ("Letter"), /*SANE_I18N ("Double letter 11x17 in"), SANE_I18N ("B4"), */ SANE_I18N ("B5"), SANE_I18N ("B6"), SANE_I18N ("Legal"), NULL }; static const int go_paper_val[] = { 0x00, 0x01, 0x02, /*0x03, *//* A3 : not supported */ 0x04, 0x05, 0x06, 0x07, /*0x09, 0x0C, *//* Dbl letter and B4 : not supported */ 0x0D, 0x0E, 0x0F }; static const KV_PAPER_SIZE go_paper_sizes[] = { {210, 297}, /* User defined, default=A4 */ {54, 90}, /* Business card */ {80, 170}, /* Check (China business) */ /*{297, 420}, *//* A3 */ {210, 297}, /* A4 */ {148, 210}, /* A5 */ {105, 148}, /* A6 */ {216, 280}, /* US Letter 8.5 x 11 in */ /*{280, 432}, *//* Double Letter 11 x 17 in */ /*{250, 353}, *//* B4 */ {176, 250}, /* B5 */ {125, 176}, /* B6 */ {216, 356} /* US Legal */ }; static const int default_paper_size_idx = 3; /* A4 */ /* Lists of supported halftone. They are only valid with * for the Black&White mode. */ static SANE_String_Const go_halftone_pattern_list[] = { SANE_I18N ("bayer_64"), SANE_I18N ("bayer_16"), SANE_I18N ("halftone_32"), SANE_I18N ("halftone_64"), SANE_I18N ("diffusion"), NULL }; static const int go_halftone_pattern_val[] = { 0x00, 0x01, 0x02, 0x03, 0x04 }; /* List of automatic threshold options */ static SANE_String_Const go_automatic_threshold_list[] = { SANE_I18N ("normal"), SANE_I18N ("light"), SANE_I18N ("dark"), NULL }; static const int go_automatic_threshold_val[] = { 0, 0x11, 0x1f }; /* List of white level base. */ static SANE_String_Const go_white_level_list[] = { SANE_I18N ("From scanner"), SANE_I18N ("From paper"), SANE_I18N ("Automatic"), NULL }; static const int go_white_level_val[] = { 0x00, 0x80, 0x81 }; /* List of noise reduction options. */ static SANE_String_Const go_noise_reduction_list[] = { SANE_I18N ("default"), "1x1", "2x2", "3x3", "4x4", "5x5", NULL }; static const int go_noise_reduction_val[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; /* List of image emphasis options, 5 steps */ static SANE_String_Const go_image_emphasis_list[] = { SANE_I18N ("smooth"), SANE_I18N ("none"), SANE_I18N ("low"), SANE_I18N ("medium"), /* default */ SANE_I18N ("high"), NULL }; static const int go_image_emphasis_val[] = { 0x14, 0x00, 0x11, 0x12, 0x13 }; /* List of gamma */ static SANE_String_Const go_gamma_list[] = { SANE_I18N ("normal"), SANE_I18N ("crt"), SANE_I18N ("linear"), NULL }; static const int go_gamma_val[] = { 0x00, 0x01, 0x02 }; /* List of lamp color dropout */ static SANE_String_Const go_lamp_list[] = { SANE_I18N ("normal"), SANE_I18N ("red"), SANE_I18N ("green"), SANE_I18N ("blue"), NULL }; static const int go_lamp_val[] = { 0x00, 0x01, 0x02, 0x03 }; static SANE_Range go_value_range = { 0, 255, 0 }; static SANE_Range go_jpeg_compression_range = { 0, 0x64, 0 }; static SANE_Range go_rotate_range = { 0, 270, 90 }; static SANE_Range go_swdespeck_range = { 0, 9, 1 }; static SANE_Range go_swskip_range = { SANE_FIX(0), SANE_FIX(100), 1 }; static const char *go_option_name[] = { "OPT_NUM_OPTS", /* General options */ "OPT_MODE_GROUP", "OPT_MODE", /* scanner modes */ "OPT_RESOLUTION", /* X and Y resolution */ "OPT_DUPLEX", /* Duplex mode */ "OPT_SCAN_SOURCE", /* Scan source, fixed to ADF */ "OPT_FEEDER_MODE", /* Feeder mode, fixed to Continuous */ "OPT_LONGPAPER", /* Long paper mode */ "OPT_LENGTHCTL", /* Length control mode */ "OPT_MANUALFEED", /* Manual feed mode */ "OPT_FEED_TIMEOUT", /* Feed timeout */ "OPT_DBLFEED", /* Double feed detection mode */ "OPT_FIT_TO_PAGE", /* Scanner shrinks image to fit scanned page */ /* Geometry group */ "OPT_GEOMETRY_GROUP", "OPT_PAPER_SIZE", /* Paper size */ "OPT_LANDSCAPE", /* true if landscape */ "OPT_TL_X", /* upper left X */ "OPT_TL_Y", /* upper left Y */ "OPT_BR_X", /* bottom right X */ "OPT_BR_Y", /* bottom right Y */ "OPT_ENHANCEMENT_GROUP", "OPT_BRIGHTNESS", /* Brightness */ "OPT_CONTRAST", /* Contrast */ "OPT_AUTOMATIC_THRESHOLD", /* Binary threshold */ "OPT_HALFTONE_PATTERN", /* Halftone pattern */ "OPT_AUTOMATIC_SEPARATION", /* Automatic separation */ "OPT_WHITE_LEVEL", /* White level */ "OPT_NOISE_REDUCTION", /* Noise reduction */ "OPT_IMAGE_EMPHASIS", /* Image emphasis */ "OPT_GAMMA", /* Gamma */ "OPT_LAMP", /* Lamp -- color drop out */ "OPT_INVERSE", /* Inverse image */ "OPT_MIRROR", /* Mirror image */ "OPT_JPEG", /* JPEG Compression */ "OPT_ROTATE", /* Rotate image */ "OPT_SWDESKEW", /* Software deskew */ "OPT_SWDESPECK", /* Software despeckle */ "OPT_SWDEROTATE", /* Software detect/correct 90 deg. rotation */ "OPT_SWCROP", /* Software autocrop */ "OPT_SWSKIP", /* Software blank page skip */ /* must come last: */ "OPT_NUM_OPTIONS" }; /* Round to boundry, return 1 if value modified */ static int round_to_boundry (SANE_Word * pval, SANE_Word boundry, SANE_Word minv, SANE_Word maxv) { SANE_Word lower, upper, k, v; v = *pval; k = v / boundry; lower = k * boundry; upper = (k + 1) * boundry; if (v - lower <= upper - v) { *pval = lower; } else { *pval = upper; } if ((*pval) < minv) *pval = minv; if ((*pval) > maxv) *pval = maxv; return ((*pval) != v); } /* Returns the length of the longest string, including the terminating * character. */ static size_t max_string_size (SANE_String_Const * strings) { size_t size, max_size = 0; int i; for (i = 0; strings[i]; ++i) { size = strlen (strings[i]) + 1; if (size > max_size) { max_size = size; } } return max_size; } /* Lookup a string list from one array and return its index. */ static int get_string_list_index (const SANE_String_Const * list, SANE_String_Const name) { int index; index = 0; while (list[index] != NULL) { if (strcmp (list[index], name) == 0) { return (index); } index++; } DBG (DBG_error, "System bug: option %s not found in list\n", name); return (-1); /* not found */ } /* Lookup a string list from one array and return the correnpond value. */ int get_optval_list (const PKV_DEV dev, int idx, const SANE_String_Const * str_list, const int *val_list) { int index; index = get_string_list_index (str_list, dev->val[idx].s); if (index < 0) index = 0; return val_list[index]; } /* Get device mode from device options */ KV_SCAN_MODE kv_get_mode (const PKV_DEV dev) { int i; i = get_string_list_index (go_scan_mode_list, dev->val[OPT_MODE].s); switch (i) { case 0: return SM_BINARY; case 1: return SM_DITHER; case 2: return SM_GRAYSCALE; case 3: return SM_COLOR; default: assert (0 == 1); return 0; } } void kv_calc_paper_size (const PKV_DEV dev, int *w, int *h) { int i = get_string_list_index (go_paper_list, dev->val[OPT_PAPER_SIZE].s); if (i == 0) { /* Non-standard document */ int x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w)); int y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w)); int x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w)); int y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w)); *w = x_br - x_tl; *h = y_br - y_tl; } else { if (dev->val[OPT_LANDSCAPE].s) { *h = mmToIlu (go_paper_sizes[i].width); *w = mmToIlu (go_paper_sizes[i].height); } else { *w = mmToIlu (go_paper_sizes[i].width); *h = mmToIlu (go_paper_sizes[i].height); } } } /* Get bit depth from scan mode */ int kv_get_depth (KV_SCAN_MODE mode) { switch (mode) { case SM_BINARY: case SM_DITHER: return 1; case SM_GRAYSCALE: return 8; case SM_COLOR: return 24; default: assert (0 == 1); return 0; } } const SANE_Option_Descriptor * kv_get_option_descriptor (PKV_DEV dev, SANE_Int option) { DBG (DBG_proc, "sane_get_option_descriptor: enter, option %s\n", go_option_name[option]); if ((unsigned) option >= OPT_NUM_OPTIONS) { return NULL; } DBG (DBG_proc, "sane_get_option_descriptor: exit\n"); return dev->opt + option; } /* Reset the options for that scanner. */ void kv_init_options (PKV_DEV dev) { int i; if (dev->option_set) return; DBG (DBG_proc, "kv_init_options: enter\n"); /* Pre-initialize the options. */ memset (dev->opt, 0, sizeof (dev->opt)); memset (dev->val, 0, sizeof (dev->val)); for (i = 0; i < OPT_NUM_OPTIONS; ++i) { dev->opt[i].size = sizeof (SANE_Word); dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; } /* Number of options. */ dev->opt[OPT_NUM_OPTS].name = ""; dev->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; dev->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; dev->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; dev->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; dev->val[OPT_NUM_OPTS].w = OPT_NUM_OPTIONS; /* Mode group */ dev->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); dev->opt[OPT_MODE_GROUP].desc = ""; /* not valid for a group */ dev->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; dev->opt[OPT_MODE_GROUP].cap = 0; dev->opt[OPT_MODE_GROUP].size = 0; dev->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; /* Scanner supported modes */ dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; dev->opt[OPT_MODE].type = SANE_TYPE_STRING; dev->opt[OPT_MODE].size = max_string_size (go_scan_mode_list); dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_MODE].constraint.string_list = go_scan_mode_list; dev->val[OPT_MODE].s = strdup (""); /* will be set later */ /* X and Y resolution */ dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; dev->opt[OPT_RESOLUTION].constraint.word_list = go_resolutions_list; dev->val[OPT_RESOLUTION].w = go_resolutions_list[3]; /* Duplex */ dev->opt[OPT_DUPLEX].name = SANE_NAME_DUPLEX; dev->opt[OPT_DUPLEX].title = SANE_TITLE_DUPLEX; dev->opt[OPT_DUPLEX].desc = SANE_DESC_DUPLEX; dev->opt[OPT_DUPLEX].type = SANE_TYPE_BOOL; dev->opt[OPT_DUPLEX].unit = SANE_UNIT_NONE; dev->val[OPT_DUPLEX].w = SANE_FALSE; if (!dev->support_info.support_duplex) dev->opt[OPT_DUPLEX].cap |= SANE_CAP_INACTIVE; /* Scan source */ dev->opt[OPT_SCAN_SOURCE].name = SANE_NAME_SCAN_SOURCE; dev->opt[OPT_SCAN_SOURCE].title = SANE_TITLE_SCAN_SOURCE; dev->opt[OPT_SCAN_SOURCE].desc = SANE_I18N ("Sets the scan source"); dev->opt[OPT_SCAN_SOURCE].type = SANE_TYPE_STRING; dev->opt[OPT_SCAN_SOURCE].size = max_string_size (go_scan_source_list); dev->opt[OPT_SCAN_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_SCAN_SOURCE].constraint.string_list = go_scan_source_list; dev->val[OPT_SCAN_SOURCE].s = strdup (go_scan_source_list[0]); dev->opt[OPT_SCAN_SOURCE].cap &= ~SANE_CAP_SOFT_SELECT; /* for KV-S1020C / KV-S1025C, scan source is fixed to ADF */ /* Feeder mode */ dev->opt[OPT_FEEDER_MODE].name = "feeder-mode"; dev->opt[OPT_FEEDER_MODE].title = SANE_I18N ("Feeder mode"); dev->opt[OPT_FEEDER_MODE].desc = SANE_I18N ("Sets the feeding mode"); dev->opt[OPT_FEEDER_MODE].type = SANE_TYPE_STRING; dev->opt[OPT_FEEDER_MODE].size = max_string_size (go_feeder_mode_list); dev->opt[OPT_FEEDER_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_FEEDER_MODE].constraint.string_list = go_feeder_mode_list; dev->val[OPT_FEEDER_MODE].s = strdup (go_feeder_mode_list[1]); /* Long paper */ dev->opt[OPT_LONGPAPER].name = SANE_NAME_LONGPAPER; dev->opt[OPT_LONGPAPER].title = SANE_TITLE_LONGPAPER; dev->opt[OPT_LONGPAPER].desc = SANE_I18N ("Enable/Disable long paper mode"); dev->opt[OPT_LONGPAPER].type = SANE_TYPE_BOOL; dev->opt[OPT_LONGPAPER].unit = SANE_UNIT_NONE; dev->val[OPT_LONGPAPER].w = SANE_FALSE; /* Length control */ dev->opt[OPT_LENGTHCTL].name = SANE_NAME_LENGTHCTL; dev->opt[OPT_LENGTHCTL].title = SANE_TITLE_LENGTHCTL; dev->opt[OPT_LENGTHCTL].desc = SANE_I18N ("Enable/Disable length control mode"); dev->opt[OPT_LENGTHCTL].type = SANE_TYPE_BOOL; dev->opt[OPT_LENGTHCTL].unit = SANE_UNIT_NONE; dev->val[OPT_LENGTHCTL].w = SANE_TRUE; /* Manual feed */ dev->opt[OPT_MANUALFEED].name = SANE_NAME_MANUALFEED; dev->opt[OPT_MANUALFEED].title = SANE_TITLE_MANUALFEED; dev->opt[OPT_MANUALFEED].desc = SANE_I18N ("Sets the manual feed mode"); dev->opt[OPT_MANUALFEED].type = SANE_TYPE_STRING; dev->opt[OPT_MANUALFEED].size = max_string_size (go_manual_feed_list); dev->opt[OPT_MANUALFEED].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_MANUALFEED].constraint.string_list = go_manual_feed_list; dev->val[OPT_MANUALFEED].s = strdup (go_manual_feed_list[0]); /*Manual feed timeout */ dev->opt[OPT_FEED_TIMEOUT].name = SANE_NAME_FEED_TIMEOUT; dev->opt[OPT_FEED_TIMEOUT].title = SANE_TITLE_FEED_TIMEOUT; dev->opt[OPT_FEED_TIMEOUT].desc = SANE_I18N ("Sets the manual feed timeout in seconds"); dev->opt[OPT_FEED_TIMEOUT].type = SANE_TYPE_INT; dev->opt[OPT_FEED_TIMEOUT].unit = SANE_UNIT_NONE; dev->opt[OPT_FEED_TIMEOUT].size = sizeof (SANE_Int); dev->opt[OPT_FEED_TIMEOUT].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_FEED_TIMEOUT].constraint.range = &(go_value_range); dev->opt[OPT_FEED_TIMEOUT].cap |= SANE_CAP_INACTIVE; dev->val[OPT_FEED_TIMEOUT].w = 30; /* Double feed */ dev->opt[OPT_DBLFEED].name = SANE_NAME_DBLFEED; dev->opt[OPT_DBLFEED].title = SANE_TITLE_DBLFEED; dev->opt[OPT_DBLFEED].desc = SANE_I18N ("Enable/Disable double feed detection"); dev->opt[OPT_DBLFEED].type = SANE_TYPE_BOOL; dev->opt[OPT_DBLFEED].unit = SANE_UNIT_NONE; dev->val[OPT_DBLFEED].w = SANE_FALSE; /* Fit to page */ dev->opt[OPT_FIT_TO_PAGE].name = SANE_I18N ("fit-to-page"); dev->opt[OPT_FIT_TO_PAGE].title = SANE_I18N ("Fit to page"); dev->opt[OPT_FIT_TO_PAGE].desc = SANE_I18N ("Scanner shrinks image to fit scanned page"); dev->opt[OPT_FIT_TO_PAGE].type = SANE_TYPE_BOOL; dev->opt[OPT_FIT_TO_PAGE].unit = SANE_UNIT_NONE; dev->val[OPT_FIT_TO_PAGE].w = SANE_FALSE; /* Geometry group */ dev->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); dev->opt[OPT_GEOMETRY_GROUP].desc = ""; /* not valid for a group */ dev->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; dev->opt[OPT_GEOMETRY_GROUP].cap = 0; dev->opt[OPT_GEOMETRY_GROUP].size = 0; dev->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; /* Paper sizes list */ dev->opt[OPT_PAPER_SIZE].name = SANE_NAME_PAPER_SIZE; dev->opt[OPT_PAPER_SIZE].title = SANE_TITLE_PAPER_SIZE; dev->opt[OPT_PAPER_SIZE].desc = SANE_DESC_PAPER_SIZE; dev->opt[OPT_PAPER_SIZE].type = SANE_TYPE_STRING; dev->opt[OPT_PAPER_SIZE].size = max_string_size (go_paper_list); dev->opt[OPT_PAPER_SIZE].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_PAPER_SIZE].constraint.string_list = go_paper_list; dev->val[OPT_PAPER_SIZE].s = strdup (""); /* will be set later */ /* Landscape */ dev->opt[OPT_LANDSCAPE].name = SANE_NAME_LANDSCAPE; dev->opt[OPT_LANDSCAPE].title = SANE_TITLE_LANDSCAPE; dev->opt[OPT_LANDSCAPE].desc = SANE_I18N ("Set paper position : " "true for landscape, false for portrait"); dev->opt[OPT_LANDSCAPE].type = SANE_TYPE_BOOL; dev->opt[OPT_LANDSCAPE].unit = SANE_UNIT_NONE; dev->val[OPT_LANDSCAPE].w = SANE_FALSE; /* Upper left X */ dev->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; dev->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; dev->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; dev->opt[OPT_TL_X].type = SANE_TYPE_FIXED; dev->opt[OPT_TL_X].unit = SANE_UNIT_MM; dev->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_TL_X].constraint.range = &(dev->x_range); /* Upper left Y */ dev->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; dev->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; dev->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; dev->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; dev->opt[OPT_TL_Y].unit = SANE_UNIT_MM; dev->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_TL_Y].constraint.range = &(dev->y_range); /* Bottom-right x */ dev->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; dev->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; dev->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; dev->opt[OPT_BR_X].type = SANE_TYPE_FIXED; dev->opt[OPT_BR_X].unit = SANE_UNIT_MM; dev->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_BR_X].constraint.range = &(dev->x_range); /* Bottom-right y */ dev->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; dev->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; dev->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; dev->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; dev->opt[OPT_BR_Y].unit = SANE_UNIT_MM; dev->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_BR_Y].constraint.range = &(dev->y_range); /* Enhancement group */ dev->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); dev->opt[OPT_ENHANCEMENT_GROUP].desc = ""; /* not valid for a group */ dev->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; dev->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED; dev->opt[OPT_ENHANCEMENT_GROUP].size = 0; dev->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; /* Brightness */ dev->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; dev->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; dev->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; dev->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; dev->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; dev->opt[OPT_BRIGHTNESS].size = sizeof (SANE_Int); dev->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_BRIGHTNESS].constraint.range = &(go_value_range); dev->val[OPT_BRIGHTNESS].w = 128; /* Contrast */ dev->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; dev->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; dev->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; dev->opt[OPT_CONTRAST].type = SANE_TYPE_INT; dev->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; dev->opt[OPT_CONTRAST].size = sizeof (SANE_Int); dev->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_CONTRAST].constraint.range = &(go_value_range); dev->val[OPT_CONTRAST].w = 128; /* Automatic threshold */ dev->opt[OPT_AUTOMATIC_THRESHOLD].name = "automatic-threshold"; dev->opt[OPT_AUTOMATIC_THRESHOLD].title = SANE_I18N ("Automatic threshold"); dev->opt[OPT_AUTOMATIC_THRESHOLD].desc = SANE_I18N ("Automatically sets brightness, contrast, white level, " "gamma, noise reduction and image emphasis"); dev->opt[OPT_AUTOMATIC_THRESHOLD].type = SANE_TYPE_STRING; dev->opt[OPT_AUTOMATIC_THRESHOLD].size = max_string_size (go_automatic_threshold_list); dev->opt[OPT_AUTOMATIC_THRESHOLD].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_AUTOMATIC_THRESHOLD].constraint.string_list = go_automatic_threshold_list; dev->val[OPT_AUTOMATIC_THRESHOLD].s = strdup (go_automatic_threshold_list[0]); /* Halftone pattern */ dev->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN; dev->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN; dev->opt[OPT_HALFTONE_PATTERN].desc = SANE_DESC_HALFTONE_PATTERN; dev->opt[OPT_HALFTONE_PATTERN].type = SANE_TYPE_STRING; dev->opt[OPT_HALFTONE_PATTERN].size = max_string_size (go_halftone_pattern_list); dev->opt[OPT_HALFTONE_PATTERN].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_HALFTONE_PATTERN].constraint.string_list = go_halftone_pattern_list; dev->val[OPT_HALFTONE_PATTERN].s = strdup (go_halftone_pattern_list[0]); /* Automatic separation */ dev->opt[OPT_AUTOMATIC_SEPARATION].name = SANE_NAME_AUTOSEP; dev->opt[OPT_AUTOMATIC_SEPARATION].title = SANE_TITLE_AUTOSEP; dev->opt[OPT_AUTOMATIC_SEPARATION].desc = SANE_DESC_AUTOSEP; dev->opt[OPT_AUTOMATIC_SEPARATION].type = SANE_TYPE_BOOL; dev->opt[OPT_AUTOMATIC_SEPARATION].unit = SANE_UNIT_NONE; dev->val[OPT_AUTOMATIC_SEPARATION].w = SANE_FALSE; /* White level base */ dev->opt[OPT_WHITE_LEVEL].name = SANE_NAME_WHITE_LEVEL; dev->opt[OPT_WHITE_LEVEL].title = SANE_TITLE_WHITE_LEVEL; dev->opt[OPT_WHITE_LEVEL].desc = SANE_DESC_WHITE_LEVEL; dev->opt[OPT_WHITE_LEVEL].type = SANE_TYPE_STRING; dev->opt[OPT_WHITE_LEVEL].size = max_string_size (go_white_level_list); dev->opt[OPT_WHITE_LEVEL].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_WHITE_LEVEL].constraint.string_list = go_white_level_list; dev->val[OPT_WHITE_LEVEL].s = strdup (go_white_level_list[0]); /* Noise reduction */ dev->opt[OPT_NOISE_REDUCTION].name = "noise-reduction"; dev->opt[OPT_NOISE_REDUCTION].title = SANE_I18N ("Noise reduction"); dev->opt[OPT_NOISE_REDUCTION].desc = SANE_I18N ("Reduce the isolated dot noise"); dev->opt[OPT_NOISE_REDUCTION].type = SANE_TYPE_STRING; dev->opt[OPT_NOISE_REDUCTION].size = max_string_size (go_noise_reduction_list); dev->opt[OPT_NOISE_REDUCTION].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_NOISE_REDUCTION].constraint.string_list = go_noise_reduction_list; dev->val[OPT_NOISE_REDUCTION].s = strdup (go_noise_reduction_list[0]); /* Image emphasis */ dev->opt[OPT_IMAGE_EMPHASIS].name = "image-emphasis"; dev->opt[OPT_IMAGE_EMPHASIS].title = SANE_I18N ("Image emphasis"); dev->opt[OPT_IMAGE_EMPHASIS].desc = SANE_I18N ("Sets the image emphasis"); dev->opt[OPT_IMAGE_EMPHASIS].type = SANE_TYPE_STRING; dev->opt[OPT_IMAGE_EMPHASIS].size = max_string_size (go_image_emphasis_list); dev->opt[OPT_IMAGE_EMPHASIS].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_IMAGE_EMPHASIS].constraint.string_list = go_image_emphasis_list; dev->val[OPT_IMAGE_EMPHASIS].s = strdup (SANE_I18N ("medium")); /* Gamma */ dev->opt[OPT_GAMMA].name = "gamma"; dev->opt[OPT_GAMMA].title = SANE_I18N ("Gamma"); dev->opt[OPT_GAMMA].desc = SANE_I18N ("Gamma"); dev->opt[OPT_GAMMA].type = SANE_TYPE_STRING; dev->opt[OPT_GAMMA].size = max_string_size (go_gamma_list); dev->opt[OPT_GAMMA].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_GAMMA].constraint.string_list = go_gamma_list; dev->val[OPT_GAMMA].s = strdup (go_gamma_list[0]); /* Lamp color dropout */ dev->opt[OPT_LAMP].name = "lamp-color"; dev->opt[OPT_LAMP].title = SANE_I18N ("Lamp color"); dev->opt[OPT_LAMP].desc = SANE_I18N ("Sets the lamp color (color dropout)"); dev->opt[OPT_LAMP].type = SANE_TYPE_STRING; dev->opt[OPT_LAMP].size = max_string_size (go_lamp_list); dev->opt[OPT_LAMP].constraint_type = SANE_CONSTRAINT_STRING_LIST; dev->opt[OPT_LAMP].constraint.string_list = go_lamp_list; dev->val[OPT_LAMP].s = strdup (go_lamp_list[0]); if (!dev->support_info.support_lamp) dev->opt[OPT_LAMP].cap |= SANE_CAP_INACTIVE; /* Inverse image */ dev->opt[OPT_INVERSE].name = SANE_NAME_INVERSE; dev->opt[OPT_INVERSE].title = SANE_TITLE_INVERSE; dev->opt[OPT_INVERSE].desc = SANE_I18N ("Inverse image in B/W or halftone mode"); dev->opt[OPT_INVERSE].type = SANE_TYPE_BOOL; dev->opt[OPT_INVERSE].unit = SANE_UNIT_NONE; dev->val[OPT_INVERSE].w = SANE_FALSE; /* Mirror image (left/right flip) */ dev->opt[OPT_MIRROR].name = SANE_NAME_MIRROR; dev->opt[OPT_MIRROR].title = SANE_TITLE_MIRROR; dev->opt[OPT_MIRROR].desc = SANE_I18N ("Mirror image (left/right flip)"); dev->opt[OPT_MIRROR].type = SANE_TYPE_BOOL; dev->opt[OPT_MIRROR].unit = SANE_UNIT_NONE; dev->val[OPT_MIRROR].w = SANE_FALSE; /* JPEG Image Compression */ dev->opt[OPT_JPEG].name = "jpeg"; dev->opt[OPT_JPEG].title = SANE_I18N ("jpeg compression"); dev->opt[OPT_JPEG].desc = SANE_I18N ("JPEG Image Compression with Q parameter, '0' - no compression"); dev->opt[OPT_JPEG].type = SANE_TYPE_INT; dev->opt[OPT_JPEG].unit = SANE_UNIT_NONE; dev->opt[OPT_JPEG].size = sizeof (SANE_Int); dev->opt[OPT_JPEG].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_JPEG].constraint.range = &(go_jpeg_compression_range); dev->val[OPT_JPEG].w = 0; /* Image Rotation */ dev->opt[OPT_ROTATE].name = "rotate"; dev->opt[OPT_ROTATE].title = SANE_I18N ("Rotate image clockwise"); dev->opt[OPT_ROTATE].desc = SANE_I18N("Request driver to rotate pages by a fixed amount"); dev->opt[OPT_ROTATE].type = SANE_TYPE_INT; dev->opt[OPT_ROTATE].unit = SANE_UNIT_NONE; dev->opt[OPT_ROTATE].size = sizeof (SANE_Int); dev->opt[OPT_ROTATE].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_ROTATE].constraint.range = &(go_rotate_range); dev->val[OPT_ROTATE].w = 0; /* Software Deskew */ dev->opt[OPT_SWDESKEW].name = "swdeskew"; dev->opt[OPT_SWDESKEW].title = SANE_I18N ("Software deskew"); dev->opt[OPT_SWDESKEW].desc = SANE_I18N("Request driver to rotate skewed pages digitally"); dev->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL; dev->opt[OPT_SWDESKEW].unit = SANE_UNIT_NONE; dev->val[OPT_SWDESKEW].w = SANE_FALSE; /* Software Despeckle */ dev->opt[OPT_SWDESPECK].name = "swdespeck"; dev->opt[OPT_SWDESPECK].title = SANE_I18N ("Software despeckle diameter"); dev->opt[OPT_SWDESPECK].desc = SANE_I18N("Maximum diameter of lone dots to remove from scan"); dev->opt[OPT_SWDESPECK].type = SANE_TYPE_INT; dev->opt[OPT_SWDESPECK].unit = SANE_UNIT_NONE; dev->opt[OPT_SWDESPECK].size = sizeof (SANE_Int); dev->opt[OPT_SWDESPECK].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_SWDESPECK].constraint.range = &(go_swdespeck_range); dev->val[OPT_SWDESPECK].w = 0; /* Software Derotate */ dev->opt[OPT_SWDEROTATE].name = "swderotate"; dev->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate"); dev->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation"); dev->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL; dev->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE; dev->val[OPT_SWDEROTATE].w = SANE_FALSE; /* Software Autocrop*/ dev->opt[OPT_SWCROP].name = "swcrop"; dev->opt[OPT_SWCROP].title = SANE_I18N ("Software automatic cropping"); dev->opt[OPT_SWCROP].desc = SANE_I18N("Request driver to remove border from pages digitally"); dev->opt[OPT_SWCROP].type = SANE_TYPE_BOOL; dev->opt[OPT_SWCROP].unit = SANE_UNIT_NONE; dev->val[OPT_SWCROP].w = SANE_FALSE; /* Software blank page skip */ dev->opt[OPT_SWSKIP].name = "swskip"; dev->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage"); dev->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels"); dev->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED; dev->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT; dev->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_SWSKIP].constraint.range = &(go_swskip_range); /* Lastly, set the default scan mode. This might change some * values previously set here. */ sane_control_option (dev, OPT_PAPER_SIZE, SANE_ACTION_SET_VALUE, (void *) go_paper_list[default_paper_size_idx], NULL); sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE, (void *) go_scan_mode_list[0], NULL); DBG (DBG_proc, "kv_init_options: exit\n"); dev->option_set = 1; } SANE_Status kv_control_option (PKV_DEV dev, SANE_Int option, SANE_Action action, void *val, SANE_Int * info) { SANE_Status status; SANE_Word cap; SANE_String_Const name; int i; SANE_Word value; DBG (DBG_proc, "sane_control_option: enter, option %s, action %s\n", go_option_name[option], action == SANE_ACTION_GET_VALUE ? "R" : "W"); if (info) { *info = 0; } if (dev->scanning) { return SANE_STATUS_DEVICE_BUSY; } if (option < 0 || option >= OPT_NUM_OPTIONS) { return SANE_STATUS_UNSUPPORTED; } cap = dev->opt[option].cap; if (!SANE_OPTION_IS_ACTIVE (cap)) { return SANE_STATUS_UNSUPPORTED; } name = dev->opt[option].name; if (!name) { name = "(no name)"; } if (action == SANE_ACTION_GET_VALUE) { switch (option) { /* word options */ case OPT_NUM_OPTS: case OPT_LONGPAPER: case OPT_LENGTHCTL: case OPT_DBLFEED: case OPT_RESOLUTION: case OPT_TL_Y: case OPT_BR_Y: case OPT_TL_X: case OPT_BR_X: case OPT_BRIGHTNESS: case OPT_CONTRAST: case OPT_DUPLEX: case OPT_LANDSCAPE: case OPT_AUTOMATIC_SEPARATION: case OPT_INVERSE: case OPT_MIRROR: case OPT_FEED_TIMEOUT: case OPT_JPEG: case OPT_ROTATE: case OPT_SWDESKEW: case OPT_SWDESPECK: case OPT_SWDEROTATE: case OPT_SWCROP: case OPT_SWSKIP: case OPT_FIT_TO_PAGE: *(SANE_Word *) val = dev->val[option].w; DBG (DBG_error, "opt value = %d\n", *(SANE_Word *) val); return SANE_STATUS_GOOD; /* string options */ case OPT_MODE: case OPT_FEEDER_MODE: case OPT_SCAN_SOURCE: case OPT_MANUALFEED: case OPT_HALFTONE_PATTERN: case OPT_PAPER_SIZE: case OPT_AUTOMATIC_THRESHOLD: case OPT_WHITE_LEVEL: case OPT_NOISE_REDUCTION: case OPT_IMAGE_EMPHASIS: case OPT_GAMMA: case OPT_LAMP: strcpy (val, dev->val[option].s); DBG (DBG_error, "opt value = %s\n", (char *) val); return SANE_STATUS_GOOD; default: return SANE_STATUS_UNSUPPORTED; } } else if (action == SANE_ACTION_SET_VALUE) { if (!SANE_OPTION_IS_SETTABLE (cap)) { DBG (DBG_error, "could not set option %s, not settable\n", go_option_name[option]); return SANE_STATUS_INVAL; } status = sanei_constrain_value (dev->opt + option, val, info); if (status != SANE_STATUS_GOOD) { DBG (DBG_error, "could not set option, invalid value\n"); return status; } switch (option) { /* Side-effect options */ case OPT_TL_Y: case OPT_BR_Y: case OPT_RESOLUTION: if (info) { *info |= SANE_INFO_RELOAD_PARAMS; } dev->val[option].w = *(SANE_Word *) val; if (option == OPT_RESOLUTION) { if (round_to_boundry (&(dev->val[option].w), dev->support_info. step_resolution, 100, 600)) { if (info) { *info |= SANE_INFO_INEXACT; } } } else if (option == OPT_TL_Y) { if (dev->val[option].w > dev->val[OPT_BR_Y].w) { dev->val[option].w = dev->val[OPT_BR_Y].w; if (info) { *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; } } } else { if (dev->val[option].w < dev->val[OPT_TL_Y].w) { dev->val[option].w = dev->val[OPT_TL_Y].w; if (info) { *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; } } } DBG (DBG_error, "option %s, input = %d, value = %d\n", go_option_name[option], (*(SANE_Word *) val), dev->val[option].w); return SANE_STATUS_GOOD; /* The length of X must be rounded (up). */ case OPT_TL_X: case OPT_BR_X: { SANE_Word xr = dev->val[OPT_RESOLUTION].w; SANE_Word tl_x = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w)) * xr; SANE_Word br_x = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w)) * xr; value = mmToIlu (SANE_UNFIX (*(SANE_Word *) val)) * xr; /* XR * W */ if (option == OPT_TL_X) { SANE_Word max = KV_PIXEL_MAX * xr - KV_PIXEL_ROUND; if (br_x < max) max = br_x; if (round_to_boundry (&value, KV_PIXEL_ROUND, 0, max)) { if (info) { *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; } } } else { if (round_to_boundry (&value, KV_PIXEL_ROUND, tl_x, KV_PIXEL_MAX * xr)) { if (info) { *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; } } } dev->val[option].w = SANE_FIX (iluToMm ((double) value / xr)); if (info) { *info |= SANE_INFO_RELOAD_PARAMS; } DBG (DBG_error, "option %s, input = %d, value = %d\n", go_option_name[option], (*(SANE_Word *) val), dev->val[option].w); return SANE_STATUS_GOOD; } case OPT_LANDSCAPE: dev->val[option].w = *(SANE_Word *) val; if (info) { *info |= SANE_INFO_RELOAD_PARAMS; } return SANE_STATUS_GOOD; /* Side-effect free options */ case OPT_CONTRAST: case OPT_BRIGHTNESS: case OPT_DUPLEX: case OPT_LONGPAPER: case OPT_LENGTHCTL: case OPT_DBLFEED: case OPT_INVERSE: case OPT_MIRROR: case OPT_AUTOMATIC_SEPARATION: case OPT_JPEG: case OPT_ROTATE: case OPT_SWDESKEW: case OPT_SWDESPECK: case OPT_SWDEROTATE: case OPT_SWCROP: case OPT_SWSKIP: case OPT_FIT_TO_PAGE: dev->val[option].w = *(SANE_Word *) val; return SANE_STATUS_GOOD; case OPT_FEED_TIMEOUT: dev->val[option].w = *(SANE_Word *) val; return CMD_set_timeout (dev, *(SANE_Word *) val); /* String mode */ case OPT_SCAN_SOURCE: case OPT_WHITE_LEVEL: case OPT_NOISE_REDUCTION: case OPT_IMAGE_EMPHASIS: case OPT_GAMMA: case OPT_LAMP: case OPT_HALFTONE_PATTERN: case OPT_FEEDER_MODE: if (strcmp (dev->val[option].s, val) == 0) return SANE_STATUS_GOOD; free (dev->val[option].s); dev->val[option].s = (SANE_String) strdup (val); if (option == OPT_FEEDER_MODE && get_string_list_index (go_feeder_mode_list, dev->val[option].s) == 1) /* continuous mode */ { free (dev->val[OPT_SCAN_SOURCE].s); dev->val[OPT_SCAN_SOURCE].s = strdup (go_scan_source_list[0]); dev->opt[OPT_LONGPAPER].cap &= ~SANE_CAP_INACTIVE; if (info) *info |= SANE_INFO_RELOAD_OPTIONS; } else { dev->opt[OPT_LONGPAPER].cap |= SANE_CAP_INACTIVE; if (info) *info |= SANE_INFO_RELOAD_OPTIONS; } if (option == OPT_SCAN_SOURCE && get_string_list_index (go_scan_source_list, dev->val[option].s) == 1) /* flatbed */ { free (dev->val[OPT_FEEDER_MODE].s); dev->val[OPT_FEEDER_MODE].s = strdup (go_feeder_mode_list[0]); } return SANE_STATUS_GOOD; case OPT_MODE: if (strcmp (dev->val[option].s, val) == 0) return SANE_STATUS_GOOD; free (dev->val[OPT_MODE].s); dev->val[OPT_MODE].s = (SANE_String) strdup (val); /* Set default options for the scan modes. */ dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_AUTOMATIC_THRESHOLD].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_AUTOMATIC_SEPARATION].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_GAMMA].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_INVERSE].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_JPEG].cap &= ~SANE_CAP_INACTIVE; if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[0]) == 0) /* binary */ { dev->opt[OPT_AUTOMATIC_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_INVERSE].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_JPEG].cap |= SANE_CAP_INACTIVE; } else if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[1]) == 0) /* halftone */ { dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_AUTOMATIC_SEPARATION].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_INVERSE].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_JPEG].cap |= SANE_CAP_INACTIVE; } else if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[2]) == 0) /* grayscale */ { dev->opt[OPT_GAMMA].cap &= ~SANE_CAP_INACTIVE; } if (info) { *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; } return SANE_STATUS_GOOD; case OPT_MANUALFEED: if (strcmp (dev->val[option].s, val) == 0) return SANE_STATUS_GOOD; free (dev->val[option].s); dev->val[option].s = (SANE_String) strdup (val); if (strcmp (dev->val[option].s, go_manual_feed_list[0]) == 0) /* off */ dev->opt[OPT_FEED_TIMEOUT].cap |= SANE_CAP_INACTIVE; else dev->opt[OPT_FEED_TIMEOUT].cap &= ~SANE_CAP_INACTIVE; if (info) *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_PAPER_SIZE: if (strcmp (dev->val[option].s, val) == 0) return SANE_STATUS_GOOD; free (dev->val[OPT_PAPER_SIZE].s); dev->val[OPT_PAPER_SIZE].s = (SANE_Char *) strdup (val); i = get_string_list_index (go_paper_list, dev->val[OPT_PAPER_SIZE].s); if (i == 0) { /*user def */ dev->opt[OPT_TL_X].cap &= dev->opt[OPT_TL_Y].cap &= dev->opt[OPT_BR_X].cap &= dev->opt[OPT_BR_Y].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_LANDSCAPE].cap |= SANE_CAP_INACTIVE; dev->val[OPT_LANDSCAPE].w = 0; } else { dev->opt[OPT_TL_X].cap |= dev->opt[OPT_TL_Y].cap |= dev->opt[OPT_BR_X].cap |= dev->opt[OPT_BR_Y].cap |= SANE_CAP_INACTIVE; if (i == 4 || i == 5 || i == 7) { /*A5, A6 or B6 */ dev->opt[OPT_LANDSCAPE].cap &= ~SANE_CAP_INACTIVE; } else { dev->opt[OPT_LANDSCAPE].cap |= SANE_CAP_INACTIVE; dev->val[OPT_LANDSCAPE].w = 0; } } if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; return SANE_STATUS_GOOD; case OPT_AUTOMATIC_THRESHOLD: if (strcmp (dev->val[option].s, val) == 0) return SANE_STATUS_GOOD; free (dev->val[option].s); dev->val[option].s = (SANE_Char *) strdup (val); /* If the threshold is not set to none, some option must * disappear. */ dev->opt[OPT_WHITE_LEVEL].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_NOISE_REDUCTION].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_IMAGE_EMPHASIS].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_AUTOMATIC_SEPARATION].cap |= SANE_CAP_INACTIVE; dev->opt[OPT_HALFTONE_PATTERN].cap |= SANE_CAP_INACTIVE; if (strcmp (val, go_automatic_threshold_list[0]) == 0) { dev->opt[OPT_WHITE_LEVEL].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_NOISE_REDUCTION].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_IMAGE_EMPHASIS].cap &= ~SANE_CAP_INACTIVE; dev->opt[OPT_AUTOMATIC_SEPARATION].cap &= ~SANE_CAP_INACTIVE; if (strcmp (dev->val[OPT_MODE].s, go_scan_mode_list[1]) == 0) { dev->opt[OPT_HALFTONE_PATTERN].cap &= ~SANE_CAP_INACTIVE; } } if (info) { *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; } return SANE_STATUS_GOOD; default: return SANE_STATUS_INVAL; } } DBG (DBG_proc, "sane_control_option: exit, bad\n"); return SANE_STATUS_UNSUPPORTED; } /* Display a buffer in the log. */ void hexdump (int level, const char *comment, unsigned char *p, int l) { int i; char line[128]; char *ptr; DBG (level, "%s\n", comment); ptr = line; for (i = 0; i < l; i++, p++) { if ((i % 16) == 0) { if (ptr != line) { *ptr = '\0'; DBG (level, "%s\n", line); ptr = line; } sprintf (ptr, "%3.3d:", i); ptr += 4; } sprintf (ptr, " %2.2x", *p); ptr += 3; } *ptr = '\0'; DBG (level, "%s\n", line); } /* Set window data */ void kv_set_window_data (PKV_DEV dev, KV_SCAN_MODE scan_mode, int side, unsigned char *windowdata) { int paper = go_paper_val[get_string_list_index (go_paper_list, dev->val[OPT_PAPER_SIZE]. s)]; /* Page side */ windowdata[0] = side; /* X and Y resolution */ Ito16 (dev->val[OPT_RESOLUTION].w, &windowdata[2]); Ito16 (dev->val[OPT_RESOLUTION].w, &windowdata[4]); /* Width and length */ if (paper == 0) { /* Non-standard document */ int x_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_X].w)); int y_tl = mmToIlu (SANE_UNFIX (dev->val[OPT_TL_Y].w)); int x_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_X].w)); int y_br = mmToIlu (SANE_UNFIX (dev->val[OPT_BR_Y].w)); int width = x_br - x_tl; int length = y_br - y_tl; /* Upper Left (X,Y) */ Ito32 (x_tl, &windowdata[6]); Ito32 (y_tl, &windowdata[10]); Ito32 (width, &windowdata[14]); Ito32 (length, &windowdata[18]); Ito32 (width, &windowdata[48]); /* device specific */ Ito32 (length, &windowdata[52]); /* device specific */ } /* Brightness */ windowdata[22] = 255 - GET_OPT_VAL_W (dev, OPT_BRIGHTNESS); windowdata[23] = windowdata[22]; /* threshold, same as brightness. */ /* Contrast */ windowdata[24] = GET_OPT_VAL_W (dev, OPT_CONTRAST); /* Image Composition */ windowdata[25] = (unsigned char) scan_mode; /* Depth */ windowdata[26] = kv_get_depth (scan_mode); /* Halftone pattern. */ if (scan_mode == SM_DITHER) { windowdata[28] = GET_OPT_VAL_L (dev, OPT_HALFTONE_PATTERN, halftone_pattern); } /* Inverse */ if (scan_mode == SM_BINARY || scan_mode == SM_DITHER) { windowdata[29] = GET_OPT_VAL_W (dev, OPT_INVERSE); } /* Bit ordering */ windowdata[31] = 1; /*Compression Type */ if (!(dev->opt[OPT_JPEG].cap & SANE_CAP_INACTIVE) && GET_OPT_VAL_W (dev, OPT_JPEG)) { windowdata[32] = 0x81; /*jpeg */ /*Compression Argument */ windowdata[33] = GET_OPT_VAL_W (dev, OPT_JPEG); } /* Gamma */ if (scan_mode == SM_DITHER || scan_mode == SM_GRAYSCALE) { windowdata[44] = GET_OPT_VAL_L (dev, OPT_GAMMA, gamma); } /* Feeder mode */ windowdata[57] = GET_OPT_VAL_L (dev, OPT_FEEDER_MODE, feeder_mode); /* Stop skew -- disabled */ windowdata[41] = 0; /* Scan source */ if (GET_OPT_VAL_L (dev, OPT_SCAN_SOURCE, scan_source)) { /* flatbed */ windowdata[41] |= 0x80; } else { windowdata[41] &= 0x7f; } /* Paper size */ windowdata[47] = paper; if (paper) /* Standard Document */ windowdata[47] |= 1 << 7; /* Long paper */ if (GET_OPT_VAL_W (dev, OPT_LONGPAPER)) { windowdata[47] |= 0x20; } /* Length control */ if (GET_OPT_VAL_W (dev, OPT_LENGTHCTL)) { windowdata[47] |= 0x40; } /* Landscape */ if (GET_OPT_VAL_W (dev, OPT_LANDSCAPE)) { windowdata[47] |= 1 << 4; } /* Double feed */ if (GET_OPT_VAL_W (dev, OPT_DBLFEED)) { windowdata[56] = 0x10; } /* Fit to page */ if (GET_OPT_VAL_W (dev, OPT_FIT_TO_PAGE)) { windowdata[56] |= 1 << 2; } /* Manual feed */ windowdata[62] = GET_OPT_VAL_L (dev, OPT_MANUALFEED, manual_feed) << 6; /* Mirror image */ if (GET_OPT_VAL_W (dev, OPT_MIRROR)) { windowdata[42] = 0x80; } /* Image emphasis */ windowdata[43] = GET_OPT_VAL_L (dev, OPT_IMAGE_EMPHASIS, image_emphasis); /* White level */ windowdata[60] = GET_OPT_VAL_L (dev, OPT_WHITE_LEVEL, white_level); if (scan_mode == SM_BINARY || scan_mode == SM_DITHER) { /* Noise reduction */ windowdata[61] = GET_OPT_VAL_L (dev, OPT_NOISE_REDUCTION, noise_reduction); /* Automatic separation */ if (scan_mode == SM_DITHER && GET_OPT_VAL_W (dev, OPT_AUTOMATIC_SEPARATION)) { windowdata[59] = 0x80; } } /* Automatic threshold. Must be last because it may override * some previous options. */ if (scan_mode == SM_BINARY) { windowdata[58] = GET_OPT_VAL_L (dev, OPT_AUTOMATIC_THRESHOLD, automatic_threshold); } if (windowdata[58] != 0) { /* Automatic threshold is enabled. */ windowdata[22] = 0; /* brightness. */ windowdata[23] = 0; /* threshold, same as brightness. */ windowdata[24] = 0; /* contrast */ windowdata[27] = windowdata[28] = 0; /* Halftone pattern. */ windowdata[43] = 0; /* Image emphasis */ windowdata[59] = 0; /* Automatic separation */ windowdata[60] = 0; /* White level */ windowdata[61] = 0; /* Noise reduction */ } /* lamp -- color dropout */ windowdata[45] = GET_OPT_VAL_L (dev, OPT_LAMP, lamp) << 4; /*Stop Mode: After 1 page */ windowdata[63] = 1; }