diff --git a/backend/coolscan2.c b/backend/coolscan2.c index 04c4d104d..53de94bed 100644 --- a/backend/coolscan2.c +++ b/backend/coolscan2.c @@ -924,9 +924,9 @@ sane_open (SANE_String_Const name, SANE_Handle * h) o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; break; case CS2_OPTION_FOCUS: - o.name = "focus"; - o.title = "Focus position"; - o.desc = "Focus position for manual focus"; + o.name = SANE_NAME_FOCUS; + o.title = SANE_TITLE_FOCUS; + o.desc = SANE_DESC_FOCUS; o.type = SANE_TYPE_INT; o.unit = SANE_UNIT_NONE; o.size = WSIZE; @@ -944,9 +944,9 @@ sane_open (SANE_String_Const name, SANE_Handle * h) } break; case CS2_OPTION_AUTOFOCUS: - o.name = "autofocus"; - o.title = "Autofocus now"; - o.desc = "Autofocus now"; + o.name = SANE_NAME_AUTOFOCUS; + o.title = SANE_TITLE_AUTOFOCUS; + o.desc = SANE_DESC_AUTOFOCUS; o.type = SANE_TYPE_BUTTON; o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; break; diff --git a/backend/coolscan3.c b/backend/coolscan3.c index 6163ec9db..5bc5b5eda 100644 --- a/backend/coolscan3.c +++ b/backend/coolscan3.c @@ -911,9 +911,9 @@ sane_open(SANE_String_Const name, SANE_Handle * h) o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; break; case CS3_OPTION_FOCUS: - o.name = "focus"; - o.title = "Focus position"; - o.desc = "Focus position for manual focus"; + o.name = SANE_NAME_FOCUS; + o.title = SANE_TITLE_FOCUS; + o.desc = SANE_DESC_FOCUS; o.type = SANE_TYPE_INT; o.unit = SANE_UNIT_NONE; o.size = WSIZE; @@ -931,9 +931,9 @@ sane_open(SANE_String_Const name, SANE_Handle * h) } break; case CS3_OPTION_AUTOFOCUS: - o.name = "autofocus"; - o.title = "Autofocus"; - o.desc = "Perform autofocus before scan"; + o.name = SANE_NAME_AUTOFOCUS; + o.title = SANE_TITLE_AUTOFOCUS; + o.desc = SANE_DESC_AUTOFOCUS; o.type = SANE_TYPE_BOOL; o.size = WSIZE; o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; diff --git a/backend/epson2-ops.c b/backend/epson2-ops.c index 1a25aaac9..f48e23a7e 100644 --- a/backend/epson2-ops.c +++ b/backend/epson2-ops.c @@ -822,24 +822,15 @@ e2_discover_capabilities(Epson_Scanner *s) if (esci_request_focus_position(s, &s->currentFocusPosition) == SANE_STATUS_GOOD) { - DBG(1, "setting focus is supported\n"); + DBG(1, "setting focus is supported, current focus: %u\n", s->currentFocusPosition); dev->focusSupport = SANE_TRUE; - s->opt[OPT_FOCUS].cap &= ~SANE_CAP_INACTIVE; - - /* reflect the current focus position in the GUI */ - if (s->currentFocusPosition < 0x4C) { - /* focus on glass */ - s->val[OPT_FOCUS].w = 0; - } else { - /* focus 2.5mm above glass */ - s->val[OPT_FOCUS].w = 1; - } - + s->opt[OPT_FOCUS_POS].cap &= ~SANE_CAP_INACTIVE; + s->val[OPT_FOCUS_POS].w = s->currentFocusPosition; } else { DBG(1, "setting focus is not supported\n"); dev->focusSupport = SANE_FALSE; - s->opt[OPT_FOCUS].cap |= SANE_CAP_INACTIVE; - s->val[OPT_FOCUS].w = 0; /* on glass - just in case */ + s->opt[OPT_FOCUS_POS].cap |= SANE_CAP_INACTIVE; + s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS; /* just in case */ } /* Set defaults for no extension. */ @@ -948,8 +939,6 @@ e2_set_extended_scanning_parameters(Epson_Scanner * s) /* ESC e */ buf[26] = extensionCtrl; - - /* XXX focus */ } /* ESC g, scanning mode (normal or high speed) */ @@ -1063,29 +1052,6 @@ e2_set_scanning_parameters(Epson_Scanner * s) * buffer to set the scan area for * ES-9000H and GT-30000 */ - - /* - * set the focus position according to the extension used: - * if the TPU is selected, then focus 2.5mm above the glass, - * otherwise focus on the glass. Scanners that don't support - * this feature, will just ignore these calls. - */ - - if (s->hw->focusSupport == SANE_TRUE) { - if (s->val[OPT_FOCUS].w == 0) { - DBG(1, "setting focus to glass surface\n"); - status = esci_set_focus_position(s, 0x40); - } else { - DBG(1, - "setting focus to 2.5mm above glass\n"); - status = esci_set_focus_position(s, 0x59); - } - - if (status != SANE_STATUS_GOOD) { - DBG(1, "setting focus failed\n"); - return status; - } - } } /* ESC C, Set color */ diff --git a/backend/epson2.c b/backend/epson2.c index a2bc5f3b7..a15a620a2 100644 --- a/backend/epson2.c +++ b/backend/epson2.c @@ -138,12 +138,6 @@ static const SANE_String_Const film_list[] = { NULL }; -static const SANE_String_Const focus_list[] = { - SANE_I18N("Focus on glass"), - SANE_I18N("Focus 2.5mm above glass"), - NULL -}; - #define HALFTONE_NONE 0x01 #define HALFTONE_TET 0x03 @@ -302,12 +296,11 @@ static const SANE_String_Const bay_list[] = { }; /* minimum, maximum, quantization */ +static const SANE_Range focus_range = { 0, 254, 0 }; static const SANE_Range u8_range = { 0, 255, 0 }; static const SANE_Range fx_range = { SANE_FIX(-2.0), SANE_FIX(2.0), 0 }; - static const SANE_Range outline_emphasis_range = { -2, 2, 0 }; - /* * List of pointers to devices - will be dynamically allocated depending * on the number of devices found. @@ -1340,6 +1333,39 @@ init_options(Epson_Scanner *s) s->opt[OPT_BR_Y].constraint.range = s->hw->y_range; s->val[OPT_BR_Y].w = s->hw->y_range->max; + /* "Focus" group: */ + s->opt[OPT_FOCUS_GROUP].title = SANE_I18N("Focus"); + s->opt[OPT_FOCUS_GROUP].desc = ""; + s->opt[OPT_FOCUS_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_FOCUS_GROUP].cap = SANE_CAP_ADVANCED; + + /* autofocus */ + s->opt[OPT_AUTOFOCUS].name = SANE_NAME_AUTOFOCUS; + s->opt[OPT_AUTOFOCUS].title = SANE_TITLE_AUTOFOCUS; + s->opt[OPT_AUTOFOCUS].desc = SANE_DESC_AUTOFOCUS; + s->opt[OPT_AUTOFOCUS].type = SANE_TYPE_BOOL; + s->val[OPT_AUTOFOCUS].w = SANE_FALSE; + s->opt[OPT_AUTOFOCUS].cap |= SANE_CAP_ADVANCED; + + /* focus position */ + s->opt[OPT_FOCUS_POS].name = SANE_NAME_FOCUS; + s->opt[OPT_FOCUS_POS].title = SANE_TITLE_FOCUS; + s->opt[OPT_FOCUS_POS].desc = SANE_DESC_FOCUS; + s->opt[OPT_FOCUS_POS].type = SANE_TYPE_INT; + s->opt[OPT_FOCUS_POS].unit = SANE_UNIT_NONE; + s->opt[OPT_FOCUS_POS].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_FOCUS_POS].constraint.range = &focus_range; + s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS; + s->opt[OPT_FOCUS_POS].cap |= SANE_CAP_ADVANCED; + + if (s->hw->focusSupport == SANE_TRUE) { + s->opt[OPT_FOCUS_POS].cap &= ~SANE_CAP_INACTIVE; + s->opt[OPT_AUTOFOCUS].cap &= ~SANE_CAP_INACTIVE; + } else { + s->opt[OPT_FOCUS_POS].cap |= SANE_CAP_INACTIVE; + s->opt[OPT_AUTOFOCUS].cap |= SANE_CAP_INACTIVE; + } + /* "Optional equipment" group: */ s->opt[OPT_EQU_GROUP].title = SANE_I18N("Optional equipment"); s->opt[OPT_EQU_GROUP].desc = ""; @@ -1376,22 +1402,6 @@ init_options(Epson_Scanner *s) if (!s->hw->cmd->set_bay) s->opt[OPT_FILM_TYPE].cap |= SANE_CAP_INACTIVE; - /* focus position */ - s->opt[OPT_FOCUS].name = SANE_EPSON_FOCUS_NAME; - s->opt[OPT_FOCUS].title = SANE_EPSON_FOCUS_TITLE; - s->opt[OPT_FOCUS].desc = SANE_EPSON_FOCUS_DESC; - s->opt[OPT_FOCUS].type = SANE_TYPE_STRING; - s->opt[OPT_FOCUS].size = max_string_size(focus_list); - s->opt[OPT_FOCUS].constraint_type = SANE_CONSTRAINT_STRING_LIST; - s->opt[OPT_FOCUS].constraint.string_list = focus_list; - s->val[OPT_FOCUS].w = 0; - s->opt[OPT_FOCUS].cap |= SANE_CAP_ADVANCED; - - if (s->hw->focusSupport == SANE_TRUE) - s->opt[OPT_FOCUS].cap &= ~SANE_CAP_INACTIVE; - else - s->opt[OPT_FOCUS].cap |= SANE_CAP_INACTIVE; - /* forward feed / eject */ s->opt[OPT_EJECT].name = "eject"; s->opt[OPT_EJECT].title = SANE_I18N("Eject"); @@ -1650,6 +1660,8 @@ getvalue(SANE_Handle handle, SANE_Int option, void *value) case OPT_THRESHOLD: case OPT_BIT_DEPTH: case OPT_WAIT_FOR_BUTTON: + case OPT_AUTOFOCUS: + case OPT_FOCUS_POS: *((SANE_Word *) value) = sval->w; break; @@ -1663,7 +1675,6 @@ getvalue(SANE_Handle handle, SANE_Int option, void *value) case OPT_GAMMA_CORRECTION: case OPT_COLOR_CORRECTION: case OPT_BAY: - case OPT_FOCUS: strcpy((char *) value, sopt->constraint.string_list[sval->w]); break; @@ -1734,8 +1745,6 @@ change_source(Epson_Scanner *s, SANE_Int optindex, char *value) if (s->hw->need_reset_on_source_change) esci_reset(s); - s->focusOnGlass = SANE_TRUE; /* this is the default */ - if (s->val[OPT_SOURCE].w == optindex) return; @@ -1754,7 +1763,7 @@ change_source(Epson_Scanner *s, SANE_Int optindex, char *value) s->hw->use_extension = SANE_TRUE; /* disable film type option */ deactivateOption(s, OPT_FILM_TYPE, &dummy); - s->val[OPT_FOCUS].w = 0; + s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS; if (s->hw->duplex) { activateOption(s, OPT_ADF_MODE, &dummy); } else { @@ -1786,10 +1795,8 @@ change_source(Epson_Scanner *s, SANE_Int optindex, char *value) deactivateOption(s, OPT_FILM_TYPE, &dummy); /* enable focus position if the scanner supports it */ - if (s->hw->cmd->set_focus_position != 0) { - s->val[OPT_FOCUS].w = 1; - s->focusOnGlass = SANE_FALSE; - } + if (s->hw->focusSupport) + s->val[OPT_FOCUS_POS].w = FOCUS_ABOVE_25MM; deactivateOption(s, OPT_ADF_MODE, &dummy); deactivateOption(s, OPT_EJECT, &dummy); @@ -1802,7 +1809,7 @@ change_source(Epson_Scanner *s, SANE_Int optindex, char *value) /* disable film type option */ deactivateOption(s, OPT_FILM_TYPE, &dummy); - s->val[OPT_FOCUS].w = 0; + s->val[OPT_FOCUS_POS].w = FOCUS_ON_GLASS; deactivateOption(s, OPT_ADF_MODE, &dummy); } @@ -1876,7 +1883,6 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) case OPT_DROPOUT: case OPT_FILM_TYPE: case OPT_BAY: - case OPT_FOCUS: sval->w = optindex; /* Simple lists */ break; @@ -1985,6 +1991,11 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) break; } + case OPT_AUTOFOCUS: + sval->w = *((SANE_Word *) value); + setOptionState(s, !sval->w, OPT_FOCUS_POS, &reload); + break; + case OPT_MIRROR: case OPT_AAS: case OPT_PREVIEW: /* needed? */ @@ -1993,6 +2004,7 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) case OPT_AUTO_EJECT: case OPT_THRESHOLD: case OPT_WAIT_FOR_BUTTON: + case OPT_FOCUS_POS: sval->w = *((SANE_Word *) value); break; @@ -2126,6 +2138,27 @@ sane_start(SANE_Handle handle) if (status != SANE_STATUS_GOOD) return status; + /* + * set focus after we set scanning parameters because the scanner will + * use the middle of the scanning area for autofocus. If we want to + * support a defined x,y position for autofocus, we'd need to send + * specific scanning paramters just for autofocus. + */ + if (s->hw->focusSupport == SANE_TRUE) { + if (s->val[OPT_AUTOFOCUS].w) { + DBG(1, "setting autofocus\n"); + status = esci_set_focus_position(s, 0xff); + } else { + DBG(1, "setting focus to %u\n", s->val[OPT_FOCUS_POS].w); + status = esci_set_focus_position(s, s->val[OPT_FOCUS_POS].w); + } + + if (status != SANE_STATUS_GOOD) { + DBG(1, "setting focus failed\n"); + return status; + } + } + /* ESC z, user defined gamma table */ if (dev->cmd->set_gamma_table && gamma_userdefined[s->val[OPT_GAMMA_CORRECTION].w]) { @@ -2231,6 +2264,12 @@ sane_start(SANE_Handle handle) if (status != SANE_STATUS_GOOD) return status; + if (s->hw->focusSupport == SANE_TRUE && s->val[OPT_AUTOFOCUS].w) { + status = esci_request_focus_position(s, &s->currentFocusPosition); + if (status == SANE_STATUS_GOOD) + s->val[OPT_FOCUS_POS].w = s->currentFocusPosition; + } + /* start scanning */ DBG(1, "%s: scanning...\n", __func__); diff --git a/backend/epson2.h b/backend/epson2.h index f439944dc..c5eadf472 100644 --- a/backend/epson2.h +++ b/backend/epson2.h @@ -80,6 +80,9 @@ #define SANE_EPSON_MAX_RETRIES 14 /* warmup max retry */ #define CMD_SIZE_EXT_STATUS 42 +#define FOCUS_ON_GLASS 64 +#define FOCUS_ABOVE_25MM (64 + 25) + /* NOTE: you can find these codes with "man ascii". */ #define STX 0x02 #define ACK 0x06 @@ -253,11 +256,13 @@ enum { OPT_TL_Y, OPT_BR_X, OPT_BR_Y, + OPT_FOCUS_GROUP, + OPT_AUTOFOCUS, + OPT_FOCUS_POS, OPT_EQU_GROUP, OPT_SOURCE, OPT_AUTO_EJECT, OPT_FILM_TYPE, - OPT_FOCUS, OPT_BAY, OPT_EJECT, OPT_ADF_MODE, @@ -387,7 +392,6 @@ struct Epson_Scanner SANE_Int lines_written; /* debug variable */ SANE_Int left, top, lcount; - SANE_Bool focusOnGlass; SANE_Byte currentFocusPosition; /* network buffers */ diff --git a/include/sane/saneopts.h b/include/sane/saneopts.h index 4a4b8cc94..35c714850 100644 --- a/include/sane/saneopts.h +++ b/include/sane/saneopts.h @@ -140,6 +140,8 @@ #define SANE_NAME_SCAN_LAMP_DEN "scan-lamp-density" #define SANE_NAME_SELECT_LAMP_DENSITY "select-lamp-density" #define SANE_NAME_LAMP_OFF_AT_EXIT "lamp-off-at-exit" +#define SANE_NAME_FOCUS "focus" +#define SANE_NAME_AUTOFOCUS "autofocus" /* well known options from 'SENSORS' group*/ #define SANE_NAME_SCAN "scan" @@ -229,6 +231,8 @@ #define SANE_TITLE_SCAN_LAMP_DEN SANE_I18N("Scan lamp density") #define SANE_TITLE_SELECT_LAMP_DENSITY SANE_I18N("Set lamp density") #define SANE_TITLE_LAMP_OFF_AT_EXIT SANE_I18N("Lamp off at exit") +#define SANE_TITLE_FOCUS SANE_I18N("Focus position") +#define SANE_TITLE_AUTOFOCUS SANE_I18N("Autofocus") /* well known options from 'SENSORS' group*/ #define SANE_TITLE_SCAN "Scan button" @@ -439,6 +443,10 @@ SANE_I18N("Define lamp density for scan") SANE_I18N("Enable selection of lamp density") #define SANE_DESC_LAMP_OFF_AT_EXIT \ SANE_I18N("Turn off lamp when program exits") +#define SANE_DESC_FOCUS \ +SANE_I18N("Focus position for manual focus") +#define SANE_DESC_AUTOFOCUS \ +SANE_I18N("Perform autofocus before scan") /* well known options from 'SENSORS' group*/ #define SANE_DESC_SCAN SANE_I18N("Scan button")