diff --git a/backend/genesys.cc b/backend/genesys.cc index 3ab1a324b..9ef9353de 100644 --- a/backend/genesys.cc +++ b/backend/genesys.cc @@ -4010,6 +4010,32 @@ max_string_size (const SANE_String_Const strings[]) return max_size; } +static unsigned pick_resolution(const std::vector& resolutions, unsigned resolution, + const char* direction) +{ + DBG_HELPER(dbg); + + if (resolutions.empty()) + throw SaneException("Empty resolution list"); + + unsigned best_res = resolutions.front(); + unsigned min_diff = abs_diff(best_res, resolution); + + for (auto it = std::next(resolutions.begin()); it != resolutions.end(); ++it) { + unsigned curr_diff = abs_diff(*it, resolution); + if (curr_diff < min_diff) { + min_diff = curr_diff; + best_res = *it; + } + } + + if (best_res != resolution) { + DBG(DBG_warn, "%s: using resolution %d that is nearest to %d for direction %s\n", + __func__, best_res, resolution, direction); + } + return best_res; +} + static void calc_parameters(Genesys_Scanner* s) { DBG_HELPER(dbg); @@ -4050,8 +4076,11 @@ static void calc_parameters(Genesys_Scanner* s) } s->dev->settings.yres = s->resolution; + s->dev->settings.xres = pick_resolution(s->dev->model->xdpi_values, s->dev->settings.xres, "X"); + s->dev->settings.yres = pick_resolution(s->dev->model->ydpi_values, s->dev->settings.yres, "Y"); + s->params.lines = ((br_y - tl_y) * s->dev->settings.yres) / MM_PER_INCH; - unsigned pixels_per_line = ((br_x - tl_x) * s->resolution) / MM_PER_INCH; + unsigned pixels_per_line = ((br_x - tl_x) * s->dev->settings.xres) / MM_PER_INCH; /* we need an even pixels number * TODO invert test logic or generalize behaviour across all ASICs */ @@ -4064,6 +4093,10 @@ static void calc_parameters(Genesys_Scanner* s) { if (s->dev->settings.xres <= 1200) { pixels_per_line = (pixels_per_line / 4) * 4; + } else if (s->dev->settings.xres < s->dev->settings.yres) { + // BUG: this is an artifact of the fact that the resolution was twice as large than + // the actual resolution when scanning above the supported scanner X resolution + pixels_per_line = (pixels_per_line / 8) * 8; } else { pixels_per_line = (pixels_per_line / 16) * 16; } @@ -4076,9 +4109,17 @@ static void calc_parameters(Genesys_Scanner* s) s->dev->model->asic_type == AsicType::GL847 || s->dev->current_setup.xres < s->dev->session.params.yres)) { - pixels_per_line = (pixels_per_line / 16) * 16; + if (s->dev->settings.xres < s->dev->settings.yres) { + // FIXME: this is an artifact of the fact that the resolution was twice as large than + // the actual resolution when scanning above the supported scanner X resolution + pixels_per_line = (pixels_per_line / 8) * 8; + } else { + pixels_per_line = (pixels_per_line / 16) * 16; + } } + unsigned xres_factor = s->resolution / s->dev->settings.xres; + unsigned bytes_per_line = 0; if (s->params.depth > 8) @@ -4119,9 +4160,9 @@ static void calc_parameters(Genesys_Scanner* s) s->dev->settings.lines = s->params.lines; s->dev->settings.pixels = pixels_per_line; - s->dev->settings.requested_pixels = pixels_per_line; - s->params.pixels_per_line = pixels_per_line; - s->params.bytes_per_line = bytes_per_line; + s->dev->settings.requested_pixels = pixels_per_line * xres_factor; + s->params.pixels_per_line = pixels_per_line * xres_factor; + s->params.bytes_per_line = bytes_per_line * xres_factor; s->dev->settings.tl_x = tl_x; s->dev->settings.tl_y = tl_y; @@ -4438,18 +4479,21 @@ static void init_options(Genesys_Scanner* s) s->opt[OPT_BIT_DEPTH].constraint.word_list = s->bpp_list; create_bpp_list (s, model->bpp_gray_values); s->bit_depth = 8; - if (s->opt[OPT_BIT_DEPTH].constraint.word_list[0] < 2) - DISABLE (OPT_BIT_DEPTH); + if (s->opt[OPT_BIT_DEPTH].constraint.word_list[0] < 2) { + DISABLE (OPT_BIT_DEPTH); + } - /* resolution */ - unsigned min_dpi = *std::min_element(model->xdpi_values.begin(), model->xdpi_values.end()); + // resolution + auto resolutions = model->get_resolutions(); - dpi_list = (SANE_Word*) malloc((model->xdpi_values.size() + 1) * sizeof(SANE_Word)); + unsigned min_dpi = *std::min_element(resolutions.begin(), resolutions.end()); + + dpi_list = (SANE_Word*) malloc((resolutions.size() + 1) * sizeof(SANE_Word)); if (!dpi_list) { throw SaneException(SANE_STATUS_NO_MEM); } - dpi_list[0] = model->xdpi_values.size(); - std::copy(model->xdpi_values.begin(), model->xdpi_values.end(), dpi_list + 1); + dpi_list[0] = resolutions.size(); + std::copy(resolutions.begin(), resolutions.end(), dpi_list + 1); s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; diff --git a/backend/genesys_device.h b/backend/genesys_device.h index 44ff53c39..3a7eddc61 100644 --- a/backend/genesys_device.h +++ b/backend/genesys_device.h @@ -178,6 +178,18 @@ struct Genesys_Model SANE_Int shading_ta_lines = 0; // how many lines are used to search start position SANE_Int search_lines = 0; + + std::vector get_resolutions() const + { + std::vector ret; + std::copy(xdpi_values.begin(), xdpi_values.end(), std::back_inserter(ret)); + std::copy(ydpi_values.begin(), ydpi_values.end(), std::back_inserter(ret)); + // sort in decreasing order + + std::sort(ret.begin(), ret.end(), std::greater()); + ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); + return ret; + } }; /** diff --git a/backend/genesys_low.h b/backend/genesys_low.h index e07a0d6b2..0f0739d95 100644 --- a/backend/genesys_low.h +++ b/backend/genesys_low.h @@ -637,6 +637,16 @@ extern void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev, void compute_session(Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor); +template +inline T abs_diff(T a, T b) +{ + if (a < b) { + return b - a; + } else { + return a - b; + } +} + /*---------------------------------------------------------------------------*/ /* ASIC specific functions declarations */ /*---------------------------------------------------------------------------*/ diff --git a/backend/genesys_settings.h b/backend/genesys_settings.h index c0e898307..24d188fa8 100644 --- a/backend/genesys_settings.h +++ b/backend/genesys_settings.h @@ -64,7 +64,7 @@ struct Genesys_Settings // number of lines at scan resolution unsigned int lines = 0; - // number of pixels at scan resolution + // number of pixels expected from the scanner unsigned int pixels = 0; // number of pixels expected by the frontend unsigned requested_pixels = 0; @@ -130,7 +130,11 @@ struct SetupParams { // than one CCD pixel, see CKSEL and GenesysSensor::ccd_pixels_per_system_pixel() unsigned pixels = NOT_SET; - // the number of pixels in the X direction as requested by the frontend. + // the number of pixels in the X direction as requested by the frontend. This will be different + // from `pixels` if the X resolution requested by the frontend is different than the actual + // resolution. This is only needed to compute dev->total_bytes_to_read. If 0, then the value + // is the same as pixels. + // TODO: move the computation of total_bytes_to_read to a higher layer. unsigned requested_pixels = 0; // the number of pixels in Y direction diff --git a/backend/genesys_tables_model.cc b/backend/genesys_tables_model.cc index 35679de50..c93117afa 100644 --- a/backend/genesys_tables_model.cc +++ b/backend/genesys_tables_model.cc @@ -645,7 +645,7 @@ void genesys_init_usb_device_tables() model.model_id = MODEL_CANON_LIDE_110; model.asic_type = AsicType::GL124; - model.xdpi_values = { 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }; + model.xdpi_values = { 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }; model.ydpi_values = { 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }; model.bpp_gray_values = { 16, 8 }; model.bpp_color_values = { 16, 8 }; @@ -1174,8 +1174,11 @@ void genesys_init_usb_device_tables() model.model_id = MODEL_HP_SCANJET_2300C; model.asic_type = AsicType::GL646; + // FIXME: the scanner supports 1200 ydpi, but we never scanned at this resolution so for now + // it's not supported model.xdpi_values = { 600, 300, 150, 75 }; - model.ydpi_values = { 1200, 600, 300, 150, 75 }; + model.ydpi_values = { /* 1200, */600, 300, 150, 75 }; + model.bpp_gray_values = { 16, 8 }; model.bpp_color_values = { 16, 8 };