genesys: Ensure that resolution is set to a supported one at high-level

Previously we relied on low-level implementation to detect when the
requested resolution is higher than one supported by the scanner and
seamlessly patch around so that the high-level code does not notice.
This complicates the low level implementation and results to duplicate
code.
merge-requests/145/head
Povilas Kanapickas 2019-08-18 11:13:01 +03:00
rodzic 61a055a8cf
commit a2ade50870
5 zmienionych plików z 89 dodań i 16 usunięć

Wyświetl plik

@ -4010,6 +4010,32 @@ max_string_size (const SANE_String_Const strings[])
return max_size;
}
static unsigned pick_resolution(const std::vector<unsigned>& 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;

Wyświetl plik

@ -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<unsigned> get_resolutions() const
{
std::vector<unsigned> 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<unsigned>());
ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
return ret;
}
};
/**

Wyświetl plik

@ -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<class T>
inline T abs_diff(T a, T b)
{
if (a < b) {
return b - a;
} else {
return a - b;
}
}
/*---------------------------------------------------------------------------*/
/* ASIC specific functions declarations */
/*---------------------------------------------------------------------------*/

Wyświetl plik

@ -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

Wyświetl plik

@ -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 };