epsonds: dynamically size ADF area based on DPI selection

The Epson ES-50 (and friends) supports a larger scanning area when
used at its lowest DPI setting. This adds support for switching to
the larger reported scan area when the DPI setting is at its lowest
value.

The scanner does not directly report the DPI to scan area relationship,
so this code is based on some educated guesses and experimentation.
It's been tested to work on the ES-50 with both scanimage and xsane.
Hopefully it does not interfere with any other scanners using this
backend.
merge-requests/753/head
Sean Greenslade 2022-09-03 23:09:36 -07:00
rodzic f79b04e8ff
commit a1c58d5d82
5 zmienionych plików z 76 dodań i 6 usunięć

Wyświetl plik

@ -465,6 +465,7 @@ static SANE_Status info_cb(void *userdata, char *token, int len)
int max = decode_value(value + 4 + 8, 8);
DBG(1, " ADF: max %dx%d @ 100dpi\n", min, max);
eds_set_adf_area_large(s->hw, min, max, 100);
}
}
@ -493,6 +494,7 @@ static SANE_Status info_cb(void *userdata, char *token, int len)
int max = decode_value(value + 4 + 4, 8);
DBG(1, " ADF: max %dx%d @ 100dpi\n", min, max);
eds_set_adf_area_large(s->hw, min, max, 100);
}
}

Wyświetl plik

@ -157,6 +157,25 @@ eds_set_adf_area(struct epsonds_device *dev, int x, int y, int unit)
SANE_UNFIX(dev->adf_y_range.max), unit);
}
void
eds_set_adf_area_large(struct epsonds_device *dev, int x, int y, int unit)
{
dev->adf_x_range_large.min = 0;
dev->adf_x_range_large.max = SANE_FIX(x * MM_PER_INCH / unit);
dev->adf_x_range_large.quant = 0;
dev->adf_y_range_large.min = 0;
dev->adf_y_range_large.max = SANE_FIX(y * MM_PER_INCH / unit);
dev->adf_y_range_large.quant = 0;
DBG(5, "%s: %f,%f %f,%f %d [mm]\n",
__func__,
SANE_UNFIX(dev->adf_x_range_large.min),
SANE_UNFIX(dev->adf_y_range_large.min),
SANE_UNFIX(dev->adf_x_range_large.max),
SANE_UNFIX(dev->adf_y_range_large.max), unit);
}
void
eds_set_tpu_area(struct epsonds_device *dev, int x, int y, int unit)
{

Wyświetl plik

@ -20,6 +20,7 @@ extern SANE_Status eds_add_resolution(epsonds_device *dev, int r);
extern SANE_Status eds_set_resolution_range(epsonds_device *dev, int min, int max);
extern void eds_set_fbf_area(epsonds_device *dev, int x, int y, int unit);
extern void eds_set_adf_area(epsonds_device *dev, int x, int y, int unit);
extern void eds_set_adf_area_large(epsonds_device *dev, int x, int y, int unit);
extern void eds_set_tpu_area(epsonds_device *dev, int x, int y, int unit);
extern SANE_Status eds_add_depth(epsonds_device *dev, SANE_Word depth);

Wyświetl plik

@ -1597,11 +1597,16 @@ device_detect(const char *name, int type, SANE_Status *status)
dev->alignment = dev->fbf_alignment;
} else if (s->hw->has_adf) {
if (dev->adf_x_range_large.max > 0) {
dev->x_range = &dev->adf_x_range_large;
dev->y_range = &dev->adf_y_range_large;
} else {
DBG(17, "ADF AMAX was not sent by scanner, using AREA instead\n");
dev->x_range = &dev->adf_x_range;
dev->y_range = &dev->adf_y_range;
}
dev->x_range = &dev->adf_x_range;
dev->y_range = &dev->adf_y_range;
dev->alignment = dev->adf_alignment;
} else {
DBG(0, "unable to lay on the flatbed or feed the feeder. is that a scanner??\n");
}
@ -2209,9 +2214,21 @@ change_source(epsonds_scanner *s, SANE_Int optindex, char *value)
force_max = SANE_TRUE;
}
SANE_Word min_resolution =
(s->hw->dpi_range.quant) ? s->hw->dpi_range.min : s->hw->res_list[1];
SANE_Bool in_min_resolution = (s->val[OPT_RESOLUTION].w == min_resolution);
if (strcmp(STRING_ADFFRONT, value) == 0 || strcmp(STRING_ADFDUPLEX, value) == 0) {
s->hw->x_range = &s->hw->adf_x_range;
s->hw->y_range = &s->hw->adf_y_range;
if (s->hw->adf_x_range_large.max > 0 && in_min_resolution) {
s->hw->x_range = &s->hw->adf_x_range_large;
s->hw->y_range = &s->hw->adf_y_range_large;
} else {
if(!in_min_resolution) DBG(17, "ADF AMAX was not sent by scanner, using AREA instead\n");
else DBG(17, "Not allowed to use AMAX due to DPI, using AREA instead\n");
s->hw->x_range = &s->hw->adf_x_range;
s->hw->y_range = &s->hw->adf_y_range;
}
s->hw->alignment = s->hw->adf_alignment;
@ -2317,8 +2334,37 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info)
switch (option) {
case OPT_ADF_SKEW:
case OPT_RESOLUTION:
/* Note: this includes an assumption that only the lowest DPI supports
* the large ADF area. This assumption holds true on at least the ES-50
* and friends, but other scanners need to be tested to see if this is
* universally true or not.
*/
if (strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFFRONT) == 0 || strcmp(source_list[s->val[OPT_SOURCE].w], STRING_ADFDUPLEX) == 0) {
SANE_Word min_resolution =
(s->hw->dpi_range.quant) ? s->hw->dpi_range.min : s->hw->res_list[1];
if (*((SANE_Word *) value) == min_resolution) {
DBG(17, "DPI change, setting ADF to large area\n");
s->hw->x_range = &s->hw->adf_x_range_large;
s->hw->y_range = &s->hw->adf_y_range_large;
} else {
DBG(17, "DPI change, setting ADF to normal area\n");
s->hw->x_range = &s->hw->adf_x_range;
s->hw->y_range = &s->hw->adf_y_range;
}
s->opt[OPT_BR_X].constraint.range = s->hw->x_range;
s->opt[OPT_BR_Y].constraint.range = s->hw->y_range;
if (s->val[OPT_BR_X].w > s->hw->x_range->max)
s->val[OPT_BR_X].w = s->hw->x_range->max;
if (s->val[OPT_BR_Y].w > s->hw->y_range->max)
s->val[OPT_BR_Y].w = s->hw->y_range->max;
}
// fall through
case OPT_ADF_SKEW:
case OPT_ADF_CRP:
sval->w = *((SANE_Word *) value);
reload = SANE_TRUE;

Wyświetl plik

@ -140,6 +140,8 @@ struct epsonds_device
SANE_Bool has_adf; /* adf */
SANE_Range adf_x_range; /* x range */
SANE_Range adf_y_range; /* y range */
SANE_Range adf_x_range_large; /* x range in largest scan mode (low DPI) */
SANE_Range adf_y_range_large; /* y range in largest scan mode (low DPI) */
SANE_Bool adf_is_duplex; /* supports duplex mode */
SANE_Bool adf_singlepass; /* supports single pass duplex */
SANE_Bool adf_has_skew; /* supports skew correction */