Merge branch 'genesys-simplify-param-calculation' into 'master'

genesys: Simplify scan parameter calculation

See merge request sane-project/backends!462
merge-requests/463/merge
Povilas Kanapickas 2020-05-21 20:57:48 +00:00
commit 4ee035983c
3 zmienionych plików z 355 dodań i 314 usunięć

Wyświetl plik

@ -185,7 +185,7 @@ static const SANE_Range expiration_range = {
1 /* quantization */
};
const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev)
const Genesys_Sensor& sanei_genesys_find_sensor_any(const Genesys_Device* dev)
{
DBG_HELPER(dbg);
for (const auto& sensor : *s_sensors) {
@ -196,7 +196,7 @@ const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev)
throw std::runtime_error("Given device does not have sensor defined");
}
Genesys_Sensor* find_sensor_impl(Genesys_Device* dev, unsigned dpi, unsigned channels,
Genesys_Sensor* find_sensor_impl(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels,
@ -211,7 +211,7 @@ Genesys_Sensor* find_sensor_impl(Genesys_Device* dev, unsigned dpi, unsigned cha
return nullptr;
}
bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
bool sanei_genesys_has_sensor(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels,
@ -219,8 +219,8 @@ bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channe
return find_sensor_impl(dev, dpi, channels, scan_method) != nullptr;
}
const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method)
const Genesys_Sensor& sanei_genesys_find_sensor(const Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels,
static_cast<unsigned>(scan_method));
@ -244,12 +244,14 @@ Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigne
std::vector<std::reference_wrapper<const Genesys_Sensor>>
sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method)
sanei_genesys_find_sensors_all(const Genesys_Device* dev, ScanMethod scan_method)
{
DBG_HELPER_ARGS(dbg, "scan_method: %d", static_cast<unsigned>(scan_method));
std::vector<std::reference_wrapper<const Genesys_Sensor>> ret;
for (const Genesys_Sensor& sensor : sanei_genesys_find_sensors_all_for_write(dev, scan_method)) {
ret.push_back(sensor);
for (auto& sensor : *s_sensors) {
if (dev->model->sensor_id == sensor.sensor_id && sensor.method == scan_method) {
ret.push_back(sensor);
}
}
return ret;
}
@ -4246,71 +4248,63 @@ static unsigned pick_resolution(const std::vector<unsigned>& resolutions, unsign
return best_res;
}
static void calc_parameters(Genesys_Scanner* s)
static Genesys_Settings calculate_scan_settings(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
float tl_x = 0, tl_y = 0, br_x = 0, br_y = 0;
tl_x = fixed_to_float(s->pos_top_left_x);
tl_y = fixed_to_float(s->pos_top_left_y);
br_x = fixed_to_float(s->pos_bottom_right_x);
br_y = fixed_to_float(s->pos_bottom_right_y);
const auto* dev = s->dev;
Genesys_Settings settings;
settings.scan_method = s->scan_method;
settings.scan_mode = option_string_to_scan_color_mode(s->mode);
s->params.last_frame = true; /* only single pass scanning supported */
if (s->mode == SANE_VALUE_SCAN_MODE_GRAY || s->mode == SANE_VALUE_SCAN_MODE_LINEART) {
s->params.format = SANE_FRAME_GRAY;
} else {
s->params.format = SANE_FRAME_RGB;
settings.depth = s->bit_depth;
if (settings.depth > 8) {
settings.depth = 16;
}
settings.disable_interpolation = s->disable_interpolation;
if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) {
s->params.depth = 1;
} else {
s->params.depth = s->bit_depth;
}
const auto& resolutions = dev->model->get_resolution_settings(settings.scan_method);
s->dev->settings.scan_method = s->scan_method;
const auto& resolutions = s->dev->model->get_resolution_settings(s->dev->settings.scan_method);
s->dev->settings.depth = s->bit_depth;
/* interpolation */
s->dev->settings.disable_interpolation = s->disable_interpolation;
// FIXME: use correct sensor
const auto& sensor = sanei_genesys_find_sensor_any(s->dev);
// FIXME: use correct sensor
const auto& sensor = sanei_genesys_find_sensor_any(dev);
// hardware settings
if (static_cast<unsigned>(s->resolution) > sensor.full_resolution &&
s->dev->settings.disable_interpolation)
settings.disable_interpolation)
{
s->dev->settings.xres = sensor.full_resolution;
settings.xres = sensor.full_resolution;
} else {
s->dev->settings.xres = s->resolution;
settings.xres = s->resolution;
}
s->dev->settings.yres = s->resolution;
settings.yres = s->resolution;
s->dev->settings.xres = pick_resolution(resolutions.resolutions_x, s->dev->settings.xres, "X");
s->dev->settings.yres = pick_resolution(resolutions.resolutions_y, s->dev->settings.yres, "Y");
settings.xres = pick_resolution(resolutions.resolutions_x, settings.xres, "X");
settings.yres = pick_resolution(resolutions.resolutions_y, settings.yres, "Y");
s->params.lines = static_cast<unsigned>(((br_y - tl_y) * s->dev->settings.yres) /
settings.tl_x = fixed_to_float(s->pos_top_left_x);
settings.tl_y = fixed_to_float(s->pos_top_left_y);
float br_x = fixed_to_float(s->pos_bottom_right_x);
float br_y = fixed_to_float(s->pos_bottom_right_y);
settings.lines = static_cast<unsigned>(((br_y - settings.tl_y) * settings.yres) /
MM_PER_INCH);
unsigned pixels_per_line = static_cast<unsigned>(((br_x - tl_x) * s->dev->settings.xres) /
unsigned pixels_per_line = static_cast<unsigned>(((br_x - settings.tl_x) * settings.xres) /
MM_PER_INCH);
/* we need an even pixels number
* TODO invert test logic or generalize behaviour across all ASICs */
if (has_flag(s->dev->model->flags, ModelFlag::SIS_SENSOR) ||
s->dev->model->asic_type == AsicType::GL847 ||
s->dev->model->asic_type == AsicType::GL124 ||
s->dev->model->asic_type == AsicType::GL845 ||
s->dev->model->asic_type == AsicType::GL846 ||
s->dev->model->asic_type == AsicType::GL843)
// we need an even pixels number
// TODO invert test logic or generalize behaviour across all ASICs
if (has_flag(dev->model->flags, ModelFlag::SIS_SENSOR) ||
dev->model->asic_type == AsicType::GL847 ||
dev->model->asic_type == AsicType::GL124 ||
dev->model->asic_type == AsicType::GL845 ||
dev->model->asic_type == AsicType::GL846 ||
dev->model->asic_type == AsicType::GL843)
{
if (s->dev->settings.xres <= 1200) {
if (settings.xres <= 1200) {
pixels_per_line = (pixels_per_line / 4) * 4;
} else if (s->dev->settings.xres < s->dev->settings.yres) {
} else if (settings.xres < 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;
@ -4319,14 +4313,14 @@ static void calc_parameters(Genesys_Scanner* s)
}
}
/* corner case for true lineart for sensor with several segments
* or when xres is doubled to match yres */
if (s->dev->settings.xres >= 1200 && (
s->dev->model->asic_type == AsicType::GL124 ||
s->dev->model->asic_type == AsicType::GL847 ||
s->dev->session.params.xres < s->dev->session.params.yres))
// corner case for true lineart for sensor with several segments or when xres is doubled
// to match yres */
if (settings.xres >= 1200 && (
dev->model->asic_type == AsicType::GL124 ||
dev->model->asic_type == AsicType::GL847 ||
dev->session.params.xres < dev->session.params.yres))
{
if (s->dev->settings.xres < s->dev->settings.yres) {
if (settings.xres < 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;
@ -4335,78 +4329,110 @@ static void calc_parameters(Genesys_Scanner* s)
}
}
unsigned xres_factor = s->resolution / s->dev->settings.xres;
unsigned bytes_per_line = 0;
if (s->params.depth > 8)
{
s->params.depth = 16;
bytes_per_line = 2 * pixels_per_line;
}
else if (s->params.depth == 1)
{
if (s->mode == SANE_VALUE_SCAN_MODE_LINEART || settings.depth == 1) {
// round down pixel number. This will is lossy operation, at most 7 pixels will be lost
pixels_per_line = (pixels_per_line / 8) * 8;
}
unsigned xres_factor = s->resolution / settings.xres;
settings.pixels = pixels_per_line;
settings.requested_pixels = pixels_per_line * xres_factor;
if (s->color_filter == "Red") {
settings.color_filter = ColorFilter::RED;
} else if (s->color_filter == "Green") {
settings.color_filter = ColorFilter::GREEN;
} else if (s->color_filter == "Blue") {
settings.color_filter = ColorFilter::BLUE;
} else {
settings.color_filter = ColorFilter::NONE;
}
if (s->color_filter == "None") {
settings.true_gray = 1;
} else {
settings.true_gray = 0;
}
settings.threshold = static_cast<int>(2.55f * (fixed_to_float(s->threshold)));
settings.threshold_curve = s->threshold_curve;
// brigthness and contrast only for for 8 bit scans
if (s->bit_depth <= 8) {
settings.contrast = (s->contrast * 127) / 100;
settings.brightness = (s->brightness * 127) / 100;
} else {
settings.contrast = 0;
settings.brightness = 0;
}
settings.expiration_time = s->expiration_time;
return settings;
}
static SANE_Parameters calculate_scan_parameters(const Genesys_Device& dev,
const Genesys_Settings& settings)
{
DBG_HELPER(dbg);
auto sensor = sanei_genesys_find_sensor(&dev, settings.xres, settings.get_channels(),
settings.scan_method);
auto session = dev.cmd_set->calculate_scan_session(&dev, sensor, settings);
SANE_Parameters params;
if (settings.scan_mode == ScanColorMode::GRAY ||
settings.scan_mode == ScanColorMode::LINEART)
{
params.format = SANE_FRAME_GRAY;
} else {
params.format = SANE_FRAME_RGB;
}
// only single-pass scanning supported
params.last_frame = true;
params.depth = settings.depth;
if (settings.scan_mode == ScanColorMode::LINEART) {
params.depth = 1;
}
// FIXME: add the data needed to perform the data conversion to the format used by the user
// to ScanSession.
unsigned pixels_per_line = settings.requested_pixels;
unsigned pixels_per_line_session = session.output_pixels * settings.requested_pixels / settings.pixels;
if (pixels_per_line != pixels_per_line_session) {
dbg.vlog(DBG_info, "The number of scanned pixels does not match "
"the number of requested pixels (%d vs %d), image will be stretched",
pixels_per_line_session, pixels_per_line);
}
unsigned bytes_per_line = 0;
if (params.depth == 16) {
bytes_per_line = 2 * pixels_per_line;
} else if (params.depth == 1) {
bytes_per_line = pixels_per_line / 8;
} else {
bytes_per_line = pixels_per_line;
}
if (s->params.format == SANE_FRAME_RGB) {
if (params.format == SANE_FRAME_RGB) {
bytes_per_line *= 3;
}
s->dev->settings.scan_mode = option_string_to_scan_color_mode(s->mode);
params.lines = settings.lines;
params.pixels_per_line = pixels_per_line;
params.bytes_per_line = bytes_per_line;
s->dev->settings.lines = s->params.lines;
s->dev->settings.pixels = pixels_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;
// threshold setting
s->dev->settings.threshold = static_cast<int>(2.55f * (fixed_to_float(s->threshold)));
// color filter
if (s->color_filter == "Red") {
s->dev->settings.color_filter = ColorFilter::RED;
} else if (s->color_filter == "Green") {
s->dev->settings.color_filter = ColorFilter::GREEN;
} else if (s->color_filter == "Blue") {
s->dev->settings.color_filter = ColorFilter::BLUE;
} else {
s->dev->settings.color_filter = ColorFilter::NONE;
}
// true gray
if (s->color_filter == "None") {
s->dev->settings.true_gray = 1;
} else {
s->dev->settings.true_gray = 0;
}
// threshold curve for dynamic rasterization
s->dev->settings.threshold_curve = s->threshold_curve;
/* brigthness and contrast only for for 8 bit scans */
if(s->bit_depth <= 8)
{
s->dev->settings.contrast = (s->contrast * 127) / 100;
s->dev->settings.brightness = (s->brightness * 127) / 100;
}
else
{
s->dev->settings.contrast=0;
s->dev->settings.brightness=0;
}
/* cache expiration time */
s->dev->settings.expiration_time = s->expiration_time;
return params;
}
static void calc_parameters(Genesys_Scanner* s)
{
DBG_HELPER(dbg);
s->dev->settings = calculate_scan_settings(s);
s->params = calculate_scan_parameters(*s->dev, s->dev->settings);
}
static void create_bpp_list (Genesys_Scanner * s, const std::vector<unsigned>& bpp)
{
@ -5536,12 +5562,12 @@ static void sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle)
s_scanners->push_back(Genesys_Scanner());
auto* s = &s_scanners->back();
s->dev = dev;
s->dev = dev;
s->scanning = false;
s->dev->parking = false;
s->dev->read_active = false;
s->dev->force_calibration = 0;
s->dev->line_count = 0;
dev->parking = false;
dev->read_active = false;
dev->force_calibration = 0;
dev->line_count = 0;
*handle = s;
@ -5549,18 +5575,18 @@ static void sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle)
sanei_genesys_init_structs (dev);
}
dev->cmd_set = create_cmd_set(dev->model->asic_type);
init_options(s);
DBG_INIT();
s->dev->cmd_set = create_cmd_set(s->dev->model->asic_type);
// FIXME: we create sensor tables for the sensor, this should happen when we know which sensor
// we will select
dev->cmd_set->init(dev);
// some hardware capabilities are detected through sensors
s->dev->cmd_set->update_hardware_sensors (s);
dev->cmd_set->update_hardware_sensors (s);
}
SANE_GENESYS_API_LINKAGE
@ -5592,46 +5618,42 @@ sane_close_impl(SANE_Handle handle)
return; /* oops, not a handle we know about */
}
Genesys_Scanner* s = &*it;
auto* dev = it->dev;
/* eject document for sheetfed scanners */
if (s->dev->model->is_sheetfed) {
catch_all_exceptions(__func__, [&](){ s->dev->cmd_set->eject_document(s->dev); });
}
else
{
/* in case scanner is parking, wait for the head
* to reach home position */
if (s->dev->parking) {
sanei_genesys_wait_for_home(s->dev);
// eject document for sheetfed scanners
if (dev->model->is_sheetfed) {
catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); });
} else {
// in case scanner is parking, wait for the head to reach home position
if (dev->parking) {
sanei_genesys_wait_for_home(dev);
}
}
// enable power saving before leaving
s->dev->cmd_set->save_power(s->dev, true);
dev->cmd_set->save_power(dev, true);
// here is the place to store calibration cache
if (s->dev->force_calibration == 0 && !is_testing_mode()) {
catch_all_exceptions(__func__, [&](){ write_calibration(s->dev->calibration_cache,
s->dev->calib_file); });
if (dev->force_calibration == 0 && !is_testing_mode()) {
catch_all_exceptions(__func__, [&](){ write_calibration(dev->calibration_cache,
dev->calib_file); });
}
s->dev->already_initialized = false;
s->dev->clear();
dev->already_initialized = false;
dev->clear();
// LAMP OFF : same register across all the ASICs */
s->dev->interface->write_register(0x03, 0x00);
dev->interface->write_register(0x03, 0x00);
catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().clear_halt(); });
catch_all_exceptions(__func__, [&](){ dev->interface->get_usb_device().clear_halt(); });
// we need this to avoid these ASIC getting stuck in bulk writes
catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().reset(); });
catch_all_exceptions(__func__, [&](){ dev->interface->get_usb_device().reset(); });
// not freeing s->dev because it's in the dev list
catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().close(); });
// not freeing dev because it's in the dev list
catch_all_exceptions(__func__, [&](){ dev->interface->get_usb_device().close(); });
s_scanners->erase(it);
s_scanners->erase(it);
}
SANE_GENESYS_API_LINKAGE
@ -5696,18 +5718,19 @@ static void print_option(DebugMessageHelper& dbg, const Genesys_Scanner& s, int
static void get_option_value(Genesys_Scanner* s, int option, void* val)
{
DBG_HELPER_ARGS(dbg, "option: %s (%d)", s->opt[option].name, option);
auto* dev = s->dev;
unsigned int i;
SANE_Word* table = nullptr;
std::vector<uint16_t> gamma_table;
unsigned option_size = 0;
const Genesys_Sensor* sensor = nullptr;
if (sanei_genesys_has_sensor(s->dev, s->dev->settings.xres, s->dev->settings.get_channels(),
s->dev->settings.scan_method))
if (sanei_genesys_has_sensor(dev, dev->settings.xres, dev->settings.get_channels(),
dev->settings.scan_method))
{
sensor = &sanei_genesys_find_sensor(s->dev, s->dev->settings.xres,
s->dev->settings.get_channels(),
s->dev->settings.scan_method);
sensor = &sanei_genesys_find_sensor(dev, dev->settings.xres,
dev->settings.get_channels(),
dev->settings.scan_method);
}
switch (option)
@ -5786,13 +5809,13 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
if (s->color_filter == "Red") {
gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_RED);
} else if (s->color_filter == "Blue") {
gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_BLUE);
} else {
gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_GREEN);
}
if (s->color_filter == "Red") {
gamma_table = get_gamma_table(dev, *sensor, GENESYS_RED);
} else if (s->color_filter == "Blue") {
gamma_table = get_gamma_table(dev, *sensor, GENESYS_BLUE);
} else {
gamma_table = get_gamma_table(dev, *sensor, GENESYS_GREEN);
}
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@ -5806,7 +5829,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_RED);
gamma_table = get_gamma_table(dev, *sensor, GENESYS_RED);
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@ -5820,7 +5843,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_GREEN);
gamma_table = get_gamma_table(dev, *sensor, GENESYS_GREEN);
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@ -5834,7 +5857,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
throw SaneException("Unsupported scanner mode selected");
table = reinterpret_cast<SANE_Word*>(val);
gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_BLUE);
gamma_table = get_gamma_table(dev, *sensor, GENESYS_BLUE);
option_size = s->opt[option].size / sizeof (SANE_Word);
if (gamma_table.size() != option_size) {
throw std::runtime_error("The size of the gamma tables does not match");
@ -5866,11 +5889,10 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
bool result = true;
auto session = s->dev->cmd_set->calculate_scan_session(s->dev, *sensor,
s->dev->settings);
auto session = dev->cmd_set->calculate_scan_session(dev, *sensor, dev->settings);
for (auto& cache : s->dev->calibration_cache) {
if (sanei_genesys_is_compatible_calibration(s->dev, session, &cache, false)) {
for (auto& cache : dev->calibration_cache) {
if (sanei_genesys_is_compatible_calibration(dev, session, &cache, false)) {
*reinterpret_cast<SANE_Bool*>(val) = SANE_FALSE;
}
}
@ -5889,6 +5911,7 @@ static void get_option_value(Genesys_Scanner* s, int option, void* val)
static void set_calibration_value(Genesys_Scanner* s, const char* val)
{
DBG_HELPER(dbg);
auto dev = s->dev;
std::string new_calib_path = val;
Genesys_Device::Calibration new_calibration;
@ -5903,8 +5926,8 @@ static void set_calibration_value(Genesys_Scanner* s, const char* val)
return;
}
s->dev->calibration_cache = std::move(new_calibration);
s->dev->calib_file = new_calib_path;
dev->calibration_cache = std::move(new_calibration);
dev->calib_file = new_calib_path;
s->calibration_file = new_calib_path;
DBG(DBG_info, "%s: Calibration filename set to '%s':\n", __func__, new_calib_path.c_str());
}
@ -5915,12 +5938,13 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
DBG_HELPER_ARGS(dbg, "option: %s (%d)", s->opt[option].name, option);
print_option(dbg, *s, option, val);
auto* dev = s->dev;
SANE_Word *table;
unsigned int i;
unsigned option_size = 0;
switch (option)
{
switch (option) {
case OPT_TL_X:
s->pos_top_left_x = *reinterpret_cast<SANE_Word*>(val);
calc_parameters(s);
@ -6015,7 +6039,7 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
ENABLE (OPT_THRESHOLD);
ENABLE (OPT_THRESHOLD_CURVE);
DISABLE (OPT_BIT_DEPTH);
if (s->dev->model->asic_type != AsicType::GL646 || !s->dev->model->is_cis) {
if (dev->model->asic_type != AsicType::GL646 || !dev->model->is_cis) {
ENABLE(OPT_COLOR_FILTER);
}
}
@ -6023,22 +6047,19 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
{
DISABLE (OPT_THRESHOLD);
DISABLE (OPT_THRESHOLD_CURVE);
if (s->mode == SANE_VALUE_SCAN_MODE_GRAY)
{
if (s->dev->model->asic_type != AsicType::GL646 || !s->dev->model->is_cis) {
if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) {
if (dev->model->asic_type != AsicType::GL646 || !dev->model->is_cis) {
ENABLE(OPT_COLOR_FILTER);
}
create_bpp_list (s, s->dev->model->bpp_gray_values);
s->bit_depth = s->dev->model->bpp_gray_values[0];
}
else
{
DISABLE (OPT_COLOR_FILTER);
create_bpp_list (s, s->dev->model->bpp_color_values);
s->bit_depth = s->dev->model->bpp_color_values[0];
}
}
calc_parameters(s);
create_bpp_list(s, dev->model->bpp_gray_values);
s->bit_depth = dev->model->bpp_gray_values[0];
} else {
DISABLE(OPT_COLOR_FILTER);
create_bpp_list(s, dev->model->bpp_color_values);
s->bit_depth = dev->model->bpp_color_values[0];
}
}
calc_parameters(s);
/* if custom gamma, toggle gamma table options according to the mode */
if (s->custom_gamma)
@ -6065,24 +6086,26 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
s->color_filter = reinterpret_cast<const char*>(val);
calc_parameters(s);
break;
case OPT_CALIBRATION_FILE:
if (s->dev->force_calibration == 0) {
case OPT_CALIBRATION_FILE: {
if (dev->force_calibration == 0) {
set_calibration_value(s, reinterpret_cast<const char*>(val));
}
break;
case OPT_LAMP_OFF_TIME:
if (*reinterpret_cast<SANE_Word*>(val) != s->lamp_off_time) {
s->lamp_off_time = *reinterpret_cast<SANE_Word*>(val);
s->dev->cmd_set->set_powersaving(s->dev, s->lamp_off_time);
}
break;
case OPT_EXPIRATION_TIME:
if (*reinterpret_cast<SANE_Word*>(val) != s->expiration_time) {
s->expiration_time = *reinterpret_cast<SANE_Word*>(val);
case OPT_LAMP_OFF_TIME: {
if (*reinterpret_cast<SANE_Word*>(val) != s->lamp_off_time) {
s->lamp_off_time = *reinterpret_cast<SANE_Word*>(val);
dev->cmd_set->set_powersaving(dev, s->lamp_off_time);
}
break;
}
break;
case OPT_CUSTOM_GAMMA:
case OPT_EXPIRATION_TIME: {
if (*reinterpret_cast<SANE_Word*>(val) != s->expiration_time) {
s->expiration_time = *reinterpret_cast<SANE_Word*>(val);
}
break;
}
case OPT_CUSTOM_GAMMA: {
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
s->custom_gamma = *reinterpret_cast<SANE_Bool*>(val);
@ -6108,88 +6131,96 @@ static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int
DISABLE (OPT_GAMMA_VECTOR_R);
DISABLE (OPT_GAMMA_VECTOR_G);
DISABLE (OPT_GAMMA_VECTOR_B);
for (auto& table : s->dev->gamma_override_tables) {
table.clear();
for (auto& table : dev->gamma_override_tables) {
table.clear();
}
}
}
break;
break;
}
case OPT_GAMMA_VECTOR:
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
case OPT_GAMMA_VECTOR: {
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
s->dev->gamma_override_tables[GENESYS_RED].resize(option_size);
s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
for (i = 0; i < option_size; i++) {
s->dev->gamma_override_tables[GENESYS_RED][i] = table[i];
s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
dev->gamma_override_tables[GENESYS_RED].resize(option_size);
dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
for (i = 0; i < option_size; i++) {
dev->gamma_override_tables[GENESYS_RED][i] = table[i];
dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
}
break;
}
break;
case OPT_GAMMA_VECTOR_R:
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
s->dev->gamma_override_tables[GENESYS_RED].resize(option_size);
for (i = 0; i < option_size; i++) {
s->dev->gamma_override_tables[GENESYS_RED][i] = table[i];
case OPT_GAMMA_VECTOR_R: {
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
dev->gamma_override_tables[GENESYS_RED].resize(option_size);
for (i = 0; i < option_size; i++) {
dev->gamma_override_tables[GENESYS_RED][i] = table[i];
}
break;
}
break;
case OPT_GAMMA_VECTOR_G:
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
for (i = 0; i < option_size; i++) {
s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
case OPT_GAMMA_VECTOR_G: {
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
dev->gamma_override_tables[GENESYS_GREEN].resize(option_size);
for (i = 0; i < option_size; i++) {
dev->gamma_override_tables[GENESYS_GREEN][i] = table[i];
}
break;
}
break;
case OPT_GAMMA_VECTOR_B:
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
for (i = 0; i < option_size; i++) {
s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
case OPT_GAMMA_VECTOR_B: {
table = reinterpret_cast<SANE_Word*>(val);
option_size = s->opt[option].size / sizeof (SANE_Word);
dev->gamma_override_tables[GENESYS_BLUE].resize(option_size);
for (i = 0; i < option_size; i++) {
dev->gamma_override_tables[GENESYS_BLUE][i] = table[i];
}
break;
}
break;
case OPT_CALIBRATE: {
auto& sensor = sanei_genesys_find_sensor_for_write(s->dev, s->dev->settings.xres,
s->dev->settings.get_channels(),
s->dev->settings.scan_method);
auto& sensor = sanei_genesys_find_sensor_for_write(dev, dev->settings.xres,
dev->settings.get_channels(),
dev->settings.scan_method);
catch_all_exceptions(__func__, [&]()
{
s->dev->cmd_set->save_power(s->dev, false);
genesys_scanner_calibration(s->dev, sensor);
dev->cmd_set->save_power(dev, false);
genesys_scanner_calibration(dev, sensor);
});
catch_all_exceptions(__func__, [&]()
{
s->dev->cmd_set->save_power(s->dev, true);
dev->cmd_set->save_power(dev, true);
});
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
}
case OPT_CLEAR_CALIBRATION:
s->dev->calibration_cache.clear();
case OPT_CLEAR_CALIBRATION: {
dev->calibration_cache.clear();
/* remove file */
unlink(s->dev->calib_file.c_str());
/* signals that sensors will have to be read again */
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
case OPT_FORCE_CALIBRATION:
s->dev->force_calibration = 1;
s->dev->calibration_cache.clear();
s->dev->calib_file.clear();
/* signals that sensors will have to be read again */
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
case OPT_IGNORE_OFFSETS: {
s->dev->ignore_offsets = true;
// remove file
unlink(dev->calib_file.c_str());
// signals that sensors will have to be read again
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
}
default:
DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option);
case OPT_FORCE_CALIBRATION: {
dev->force_calibration = 1;
dev->calibration_cache.clear();
dev->calib_file.clear();
// signals that sensors will have to be read again
*myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
break;
}
case OPT_IGNORE_OFFSETS: {
dev->ignore_offsets = true;
break;
}
default: {
DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option);
}
}
}
@ -6267,13 +6298,13 @@ void sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
auto* dev = s->dev;
/* don't recompute parameters once data reading is active, ie during scan */
if (!s->dev->read_active) {
if (!dev->read_active) {
calc_parameters(s);
}
if (params)
{
if (params) {
*params = s->params;
/* in the case of a sheetfed scanner, when full height is specified
@ -6281,11 +6312,11 @@ void sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params)
* don't know the real document height.
* We don't do that doing buffering image for digital processing
*/
if (s->dev->model->is_sheetfed &&
if (dev->model->is_sheetfed &&
s->pos_bottom_right_y == s->opt[OPT_BR_Y].constraint.range->max)
{
params->lines = -1;
}
params->lines = -1;
}
}
debug_dump(DBG_proc, *params);
}
@ -6303,6 +6334,7 @@ void sane_start_impl(SANE_Handle handle)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
auto* dev = s->dev;
if (s->pos_top_left_x >= s->pos_bottom_right_x) {
throw SaneException("top left x >= bottom right x");
@ -6312,33 +6344,33 @@ void sane_start_impl(SANE_Handle handle)
}
// fetch stored calibration
if (s->dev->force_calibration == 0) {
auto path = calibration_filename(s->dev);
if (dev->force_calibration == 0) {
auto path = calibration_filename(dev);
s->calibration_file = path;
s->dev->calib_file = path;
dev->calib_file = path;
DBG(DBG_info, "%s: Calibration filename set to:\n", __func__);
DBG(DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file.c_str());
DBG(DBG_info, "%s: >%s<\n", __func__, dev->calib_file.c_str());
catch_all_exceptions(__func__, [&]()
{
sanei_genesys_read_calibration(s->dev->calibration_cache, s->dev->calib_file);
sanei_genesys_read_calibration(dev->calibration_cache, dev->calib_file);
});
}
/* First make sure we have a current parameter set. Some of the
parameters will be overwritten below, but that's OK. */
// First make sure we have a current parameter set. Some of the
// parameters will be overwritten below, but that's OK.
calc_parameters(s);
genesys_start_scan(s->dev, s->lamp_off);
genesys_start_scan(dev, s->lamp_off);
s->scanning = true;
/* allocate intermediate buffer when doing dynamic lineart */
if (s->dev->settings.scan_mode == ScanColorMode::LINEART) {
s->dev->binarize_buffer.clear();
s->dev->binarize_buffer.alloc(s->dev->settings.pixels);
s->dev->local_buffer.clear();
s->dev->local_buffer.alloc(s->dev->binarize_buffer.size() * 8);
// allocate intermediate buffer when doing dynamic lineart
if (dev->settings.scan_mode == ScanColorMode::LINEART) {
dev->binarize_buffer.clear();
dev->binarize_buffer.alloc(dev->settings.pixels);
dev->local_buffer.clear();
dev->local_buffer.alloc(dev->binarize_buffer.size() * 8);
}
}
@ -6355,14 +6387,13 @@ void sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
Genesys_Device *dev;
size_t local_len;
if (!s) {
throw SaneException("handle is nullptr");
}
dev=s->dev;
auto* dev = s->dev;
if (!dev) {
throw SaneException("dev is nullptr");
}
@ -6460,35 +6491,31 @@ void sane_cancel_impl(SANE_Handle handle)
{
DBG_HELPER(dbg);
Genesys_Scanner* s = reinterpret_cast<Genesys_Scanner*>(handle);
auto* dev = s->dev;
s->scanning = false;
s->dev->read_active = false;
dev->read_active = false;
/* no need to end scan if we are parking the head */
if (!s->dev->parking) {
s->dev->cmd_set->end_scan(s->dev, &s->dev->reg, true);
// no need to end scan if we are parking the head
if (!dev->parking) {
dev->cmd_set->end_scan(dev, &dev->reg, true);
}
/* park head if flatbed scanner */
if (!s->dev->model->is_sheetfed) {
if (!s->dev->parking) {
s->dev->cmd_set->move_back_home (s->dev, has_flag(s->dev->model->flags,
ModelFlag::MUST_WAIT));
s->dev->parking = !has_flag(s->dev->model->flags, ModelFlag::MUST_WAIT);
// park head if flatbed scanner
if (!dev->model->is_sheetfed) {
if (!dev->parking) {
dev->cmd_set->move_back_home(dev, has_flag(dev->model->flags, ModelFlag::MUST_WAIT));
dev->parking = !has_flag(dev->model->flags, ModelFlag::MUST_WAIT);
}
}
else
{ /* in case of sheetfed scanners, we have to eject the document if still present */
s->dev->cmd_set->eject_document(s->dev);
} else {
// in case of sheetfed scanners, we have to eject the document if still present
dev->cmd_set->eject_document(dev);
}
/* enable power saving mode unless we are parking .... */
if (!s->dev->parking) {
s->dev->cmd_set->save_power(s->dev, true);
// enable power saving mode unless we are parking ....
if (!dev->parking) {
dev->cmd_set->save_power(dev, true);
}
return;
}
SANE_GENESYS_API_LINKAGE

Wyświetl plik

@ -225,16 +225,16 @@ extern void sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t
extern void sanei_genesys_init_structs (Genesys_Device * dev);
const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev);
const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi,
const Genesys_Sensor& sanei_genesys_find_sensor_any(const Genesys_Device* dev);
const Genesys_Sensor& sanei_genesys_find_sensor(const Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method);
bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels,
bool sanei_genesys_has_sensor(const Genesys_Device* dev, unsigned dpi, unsigned channels,
ScanMethod scan_method);
Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigned dpi,
unsigned channels, ScanMethod scan_method);
std::vector<std::reference_wrapper<const Genesys_Sensor>>
sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method);
sanei_genesys_find_sensors_all(const Genesys_Device* dev, ScanMethod scan_method);
std::vector<std::reference_wrapper<Genesys_Sensor>>
sanei_genesys_find_sensors_all_for_write(Genesys_Device* dev, ScanMethod scan_method);

Wyświetl plik

@ -199,7 +199,19 @@ private:
};
void build_checkpoint(const genesys::Genesys_Device& dev,
void print_params(const SANE_Parameters& params, std::stringstream& out)
{
out << "\n\n================\n"
<< "Scan params:\n"
<< "format: " << params.format << "\n"
<< "last_frame: " << params.last_frame << "\n"
<< "bytes_per_line: " << params.bytes_per_line << "\n"
<< "pixels_per_line: " << params.pixels_per_line << "\n"
<< "lines: " << params.lines << "\n"
<< "depth: " << params.depth << "\n";
}
void print_checkpoint(const genesys::Genesys_Device& dev,
genesys::TestScannerInterface& iface,
const std::string& checkpoint_name,
std::stringstream& out)
@ -240,15 +252,15 @@ void build_checkpoint(const genesys::Genesys_Device& dev,
void run_single_test_scan(const TestConfig& config, std::stringstream& out)
{
auto build_checkpoint_wrapper = [&](const genesys::Genesys_Device& dev,
auto print_checkpoint_wrapper = [&](const genesys::Genesys_Device& dev,
genesys::TestScannerInterface& iface,
const std::string& checkpoint_name)
{
build_checkpoint(dev, iface, checkpoint_name, out);
print_checkpoint(dev, iface, checkpoint_name, out);
};
genesys::enable_testing_mode(config.vendor_id, config.product_id, config.bcd_device,
build_checkpoint_wrapper);
print_checkpoint_wrapper);
SANE_Handle handle;
@ -274,6 +286,8 @@ void run_single_test_scan(const TestConfig& config, std::stringstream& out)
SANE_Parameters params;
TIE(sane_get_parameters(handle, &params));
print_params(params, out);
int buffer_size = 1024 * 1024;
std::vector<std::uint8_t> buffer;
buffer.resize(buffer_size);