Merge branch 'genesys-gl841-fixes' into 'master'

genesys: Various fixes for GL841 scanners

Closes #357

See merge request sane-project/backends!673
This commit is contained in:
Povilas Kanapickas
2021-12-27 21:08:39 +00:00
15 changed files with 244 additions and 369 deletions
+3
View File
@@ -526,6 +526,9 @@ enum class ModelFlag : unsigned
// disable fast feeding mode on this scanner
DISABLE_FAST_FEEDING = 1 << 14,
// scan gray scans as color and combine on host side
HOST_SIDE_GRAY = 1 << 15,
// the scanner uses multi-segment sensors that must be handled during calibration
SIS_SENSOR = 1 << 16,
+16 -109
View File
@@ -673,9 +673,9 @@ void scanner_setup_sensor(Genesys_Device& dev, const Genesys_Sensor& sensor,
regs.set8(custom_reg.address, custom_reg.value);
}
if (dev.model->asic_type != AsicType::GL841 &&
dev.model->asic_type != AsicType::GL843)
if (dev.model->asic_type != AsicType::GL843)
{
// FIXME: remove the above check
regs_set_exposure(dev.model->asic_type, regs, sensor.exposure);
}
@@ -1884,7 +1884,8 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor&
float curr_output = 0;
float target_value = 0;
if (dev.model->asic_type == AsicType::GL842 ||
if (dev.model->asic_type == AsicType::GL841 ||
dev.model->asic_type == AsicType::GL842 ||
dev.model->asic_type == AsicType::GL843)
{
std::vector<std::uint16_t> values;
@@ -1900,18 +1901,6 @@ void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor&
curr_output = static_cast<float>(values[unsigned((values.size() - 1) * 0.95)]);
target_value = calib_sensor->gain_white_ref * coeff;
} else if (dev.model->asic_type == AsicType::GL841) {
// FIXME: use the GL843 approach
unsigned max = 0;
for (std::size_t x = 0; x < image.get_width(); x++) {
auto value = image.get_raw_channel(x, 0, ch);
if (value > max) {
max = value;
}
}
curr_output = max;
target_value = 65535.0f;
} else {
// FIXME: use the GL843 approach
auto width = image.get_width();
@@ -2009,7 +1998,8 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
const auto& calib_sensor = sanei_genesys_find_sensor(&dev, resolution, channels,
dev.settings.scan_method);
if (dev.model->asic_type == AsicType::GL845 ||
if (dev.model->asic_type == AsicType::GL841 ||
dev.model->asic_type == AsicType::GL845 ||
dev.model->asic_type == AsicType::GL846 ||
dev.model->asic_type == AsicType::GL847 ||
dev.model->asic_type == AsicType::GL124)
@@ -2017,14 +2007,9 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
regs = dev.reg; // FIXME: apply this to all ASICs
}
unsigned yres = resolution;
if (dev.model->asic_type == AsicType::GL841) {
yres = dev.settings.yres; // FIXME: remove this
}
ScanSession session;
session.params.xres = resolution;
session.params.yres = yres;
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = dev.model->x_size_calib_mm * resolution / MM_PER_INCH;
@@ -2045,27 +2030,14 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
dev.cmd_set->init_regs_for_scan_session(&dev, calib_sensor, &regs, session);
if (dev.model->asic_type == AsicType::GL841) {
dev.interface->write_registers(regs); // FIXME: remove this
}
std::uint16_t exp[3];
if (dev.model->asic_type == AsicType::GL841) {
exp[0] = sensor.exposure.red;
exp[1] = sensor.exposure.green;
exp[2] = sensor.exposure.blue;
} else {
exp[0] = calib_sensor.exposure.red;
exp[1] = calib_sensor.exposure.green;
exp[2] = calib_sensor.exposure.blue;
}
exp[0] = calib_sensor.exposure.red;
exp[1] = calib_sensor.exposure.green;
exp[2] = calib_sensor.exposure.blue;
std::uint16_t target = sensor.gain_white_ref * 256;
std::uint16_t min_exposure = 500; // only gl841
std::uint16_t max_exposure = ((exp[0] + exp[1] + exp[2]) / 3) * 2; // only gl841
std::uint16_t top[3] = {};
std::uint16_t bottom[3] = {};
@@ -2101,16 +2073,6 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
for (unsigned i_test = 0; i_test < 100 && !acceptable; ++i_test) {
regs_set_exposure(dev.model->asic_type, regs, { exp[0], exp[1], exp[2] });
if (dev.model->asic_type == AsicType::GL841) {
// FIXME: remove
dev.interface->write_register(0x10, (exp[0] >> 8) & 0xff);
dev.interface->write_register(0x11, exp[0] & 0xff);
dev.interface->write_register(0x12, (exp[1] >> 8) & 0xff);
dev.interface->write_register(0x13, exp[1] & 0xff);
dev.interface->write_register(0x14, (exp[2] >> 8) & 0xff);
dev.interface->write_register(0x15, exp[2] & 0xff);
}
dev.interface->write_registers(regs);
dbg.log(DBG_info, "starting line reading");
@@ -2121,15 +2083,13 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
if (dev.model->asic_type == AsicType::GL841) {
scanner_stop_action(dev);
dev.cmd_set->move_back_home(&dev, true);
return { exp[0], exp[1], exp[2] };
} else if (dev.model->asic_type == AsicType::GL124) {
scanner_stop_action(dev);
return calib_sensor.exposure;
} else {
scanner_stop_action(dev);
dev.cmd_set->move_back_home(&dev, true);
return calib_sensor.exposure;
}
return { exp[0], exp[1], exp[2] };
}
auto image = read_unshuffled_image_from_scanner(&dev, session, session.output_line_bytes);
@@ -2155,57 +2115,8 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
acceptable = true;
if (dev.model->asic_type == AsicType::GL841) {
if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 ||
avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 ||
avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95)
{
acceptable = false;
}
// led exposure is not acceptable if white level is too low.
// ~80 hardcoded value for white level
if (avg[0] < 20000 || avg[1] < 20000 || avg[2] < 20000) {
acceptable = false;
}
// for scanners using target value
if (target > 0) {
acceptable = true;
for (unsigned i = 0; i < 3; i++) {
// we accept +- 2% delta from target
if (std::abs(avg[i] - target) > target / 50) {
exp[i] = (exp[i] * target) / avg[i];
acceptable = false;
}
}
} else {
if (!acceptable) {
unsigned avga = (avg[0] + avg[1] + avg[2]) / 3;
exp[0] = (exp[0] * avga) / avg[0];
exp[1] = (exp[1] * avga) / avg[1];
exp[2] = (exp[2] * avga) / avg[2];
/* Keep the resulting exposures below this value. Too long exposure drives
the ccd into saturation. We may fix this by relying on the fact that
we get a striped scan without shading, by means of statistical calculation
*/
unsigned avge = (exp[0] + exp[1] + exp[2]) / 3;
if (avge > max_exposure) {
exp[0] = (exp[0] * max_exposure) / avge;
exp[1] = (exp[1] * max_exposure) / avge;
exp[2] = (exp[2] * max_exposure) / avge;
}
if (avge < min_exposure) {
exp[0] = (exp[0] * min_exposure) / avge;
exp[1] = (exp[1] * min_exposure) / avge;
exp[2] = (exp[2] * min_exposure) / avge;
}
}
}
} else if (dev.model->asic_type == AsicType::GL845 ||
dev.model->asic_type == AsicType::GL846)
if (dev.model->asic_type == AsicType::GL845 ||
dev.model->asic_type == AsicType::GL846)
{
for (unsigned i = 0; i < 3; i++) {
if (avg[i] < bottom[i]) {
@@ -2238,7 +2149,9 @@ SensorExposure scanner_led_calibration(Genesys_Device& dev, const Genesys_Sensor
acceptable = false;
}
}
} else if (dev.model->asic_type == AsicType::GL124) {
} else if (dev.model->asic_type == AsicType::GL841 ||
dev.model->asic_type == AsicType::GL124)
{
for (unsigned i = 0; i < 3; i++) {
// we accept +- 2% delta from target
if (std::abs(avg[i] - target) > target / 50) {
@@ -4370,12 +4283,6 @@ static Genesys_Settings calculate_scan_settings(Genesys_Scanner* s)
settings.color_filter = ColorFilter::NONE;
}
if (s->color_filter == "None") {
settings.true_gray = 1;
} else {
settings.true_gray = 0;
}
// brightness and contrast only for for 8 bit scans
if (s->bit_depth == 8) {
settings.contrast = (s->contrast * 127) / 100;
+1 -14
View File
@@ -453,7 +453,6 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
ScanFlag flags)
{
DBG_HELPER(dbg);
int use_fast_fed;
unsigned int lincnt, fast_dpi;
unsigned int feedl,dist;
std::uint32_t z1, z2;
@@ -467,9 +466,6 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
feed_steps, static_cast<unsigned>(scan_mode),
static_cast<unsigned>(flags));
/* we never use fast fed since we do manual feed for the scans */
use_fast_fed=0;
/* enforce motor minimal scan speed
* @TODO extend motor struct for this value */
if (scan_mode == ScanColorMode::COLOR_SINGLE_PASS)
@@ -516,12 +512,6 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
/* compute register 02 value */
std::uint8_t r02 = REG_0x02_NOTHOME;
if (use_fast_fed) {
r02 |= REG_0x02_FASTFED;
} else {
r02 &= ~REG_0x02_FASTFED;
}
if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
r02 |= REG_0x02_AGOHOME;
}
@@ -573,9 +563,6 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
if (use_fast_fed) {
dist += fast_table.table.size() * 2;
}
/* get sure we don't use insane value */
if (dist < feedl) {
@@ -587,7 +574,7 @@ static void gl124_init_motor_regs_scan(Genesys_Device* dev,
reg->set24(REG_FEEDL, feedl);
/* doesn't seem to matter that much */
sanei_genesys_calculate_zmod(use_fast_fed,
sanei_genesys_calculate_zmod(false,
scan_exposure_time,
scan_table.table,
scan_table.table.size(),
+3 -1
View File
@@ -606,7 +606,9 @@ void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Gene
}
/* true CIS gray if needed */
if (dev->model->is_cis && session.params.channels == 1 && dev->settings.true_gray) {
if (dev->model->is_cis && session.params.channels == 1 &&
session.params.color_filter == ColorFilter::NONE)
{
regs->find_reg(0x05).value |= REG_0x05_LEDADD;
} else {
regs->find_reg(0x05).value &= ~REG_0x05_LEDADD;
+29 -169
View File
@@ -149,15 +149,6 @@ gl841_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x13, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x14, 0x00); // SENSOR_DEF
dev->reg.init_reg(0x15, 0x00); // SENSOR_DEF
if (dev->model->model_id == ModelId::CANON_LIDE_80) {
dev->reg.init_reg(0x10, 0x40);
dev->reg.init_reg(0x11, 0x00);
dev->reg.init_reg(0x12, 0x40);
dev->reg.init_reg(0x13, 0x00);
dev->reg.init_reg(0x14, 0x40);
dev->reg.init_reg(0x15, 0x00);
}
dev->reg.init_reg(0x16, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
dev->reg.init_reg(0x17, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF, overwritten in scanner_setup_sensor() below
@@ -184,36 +175,21 @@ gl841_init_registers (Genesys_Device * dev)
dev->reg.init_reg(0x27, 0x00);
dev->reg.init_reg(0x29, 0xff);
dev->reg.init_reg(0x2c, 0x00);
dev->reg.init_reg(0x2d, 0x00);
if (dev->model->model_id == ModelId::CANON_LIDE_80) {
dev->reg.init_reg(0x2c, sensor.full_resolution >> 8);
dev->reg.init_reg(0x2d, sensor.full_resolution & 0xff);
}
dev->reg.init_reg(0x2c, 0x02); // DPISET: overwritten during scanner setup
dev->reg.init_reg(0x2d, 0x58); // DPISET: overwritten during scanner setup
dev->reg.init_reg(0x2e, 0x80);
dev->reg.init_reg(0x2f, 0x80);
dev->reg.init_reg(0x30, 0x00);
dev->reg.init_reg(0x31, 0x00);
dev->reg.init_reg(0x32, 0x00);
dev->reg.init_reg(0x33, 0x00);
dev->reg.init_reg(0x34, 0x00);
dev->reg.init_reg(0x35, 0x00);
dev->reg.init_reg(0x36, 0x00);
dev->reg.init_reg(0x37, 0x00);
dev->reg.init_reg(0x38, 0x4f);
dev->reg.init_reg(0x39, 0xc1);
if (dev->model->model_id == ModelId::CANON_LIDE_80) {
dev->reg.init_reg(0x31, 0x10);
dev->reg.init_reg(0x32, 0x15);
dev->reg.init_reg(0x33, 0x0e);
dev->reg.init_reg(0x34, 0x40);
dev->reg.init_reg(0x35, 0x00);
dev->reg.init_reg(0x36, 0x2a);
dev->reg.init_reg(0x37, 0x30);
dev->reg.init_reg(0x38, 0x2a);
dev->reg.init_reg(0x39, 0xf8);
}
dev->reg.init_reg(0x30, 0x00); // STRPIXEL: overwritten during scanner setup
dev->reg.init_reg(0x31, 0x00); // STRPIXEL: overwritten during scanner setup
dev->reg.init_reg(0x32, 0x00); // ENDPIXEL: overwritten during scanner setup
dev->reg.init_reg(0x33, 0x00); // ENDPIXEL: overwritten during scanner setup
dev->reg.init_reg(0x34, 0x00); // DUMMY: overwritten during scanner setup
dev->reg.init_reg(0x35, 0x00); // MAXWD: overwritten during scanner setup
dev->reg.init_reg(0x36, 0x00); // MAXWD: overwritten during scanner setup
dev->reg.init_reg(0x37, 0x00); // MAXWD: overwritten during scanner setup
dev->reg.init_reg(0x38, 0x4f); // LPERIOD: overwritten during scanner setup
dev->reg.init_reg(0x39, 0xc1); // LPERIOD: overwritten during scanner setup
dev->reg.init_reg(0x3d, 0x00);
dev->reg.init_reg(0x3e, 0x00);
@@ -330,11 +306,6 @@ gl841_init_registers (Genesys_Device * dev)
dev->interface->write_0x8c(0x10, 0x94);
dev->interface->write_register(0x09, 0x10);
// FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was
// effectively changed. The current behavior matches the old code, but should probably be fixed.
dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18;
dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17;
}
}
@@ -598,7 +569,6 @@ static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor
{
DBG_HELPER_ARGS(dbg, "feed_steps=%d, flags=%x", feed_steps, static_cast<unsigned>(flags));
unsigned step_multiplier = 2;
int use_fast_fed = 0;
unsigned int feedl;
/*number of scan lines to add in a scan_lines line*/
@@ -629,10 +599,6 @@ static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor
// BUG: fast table is counted in base_ydpi / 4
feedl = feed_steps - fast_table.table.size() * 2;
use_fast_fed = 1;
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
reg->set8(0x3d, (feedl >> 16) & 0xf);
reg->set8(0x3e, (feedl >> 8) & 0xff);
@@ -647,10 +613,6 @@ static void gl841_init_motor_regs_feed(Genesys_Device* dev, const Genesys_Sensor
reg->find_reg(0x02).value &= ~0x80; /*NOT_HOME OFF*/
reg->find_reg(0x02).value |= REG_0x02_MTRPWR;
if (use_fast_fed)
reg->find_reg(0x02).value |= 0x08;
else
reg->find_reg(0x02).value &= ~0x08;
if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
@@ -697,9 +659,6 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
unsigned step_multiplier = 2;
int use_fast_fed = 0;
unsigned int fast_time;
unsigned int slow_time;
unsigned int feedl;
unsigned int min_restep = 0x20;
@@ -736,54 +695,11 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
fast_table.slice_steps(max_fast_slope_steps_count, step_multiplier);
}
/* fast fed special cases handling */
if (dev->model->gpio_id == GpioId::XP300
|| dev->model->gpio_id == GpioId::DP685)
{
/* quirk: looks like at least this scanner is unable to use
2-feed mode */
use_fast_fed = 0;
}
else if (feed_steps < fast_table.table.size() * 2 +
(slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
{
use_fast_fed = 0;
DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__);
} else {
/* for deciding whether we should use fast mode we need to check how long we
need for (fast)accelerating, moving, decelerating, (TODO: stopping?)
(slow)accelerating again versus (slow)accelerating and moving. we need
fast and slow tables here.
*/
/*NOTE: scan_exposure_time is per scan_yres*/
/*NOTE: fast_exposure is per base_ydpi/4*/
/*we use full steps as base unit here*/
fast_time =
(fast_table.table.back() << static_cast<unsigned>(fast_profile->step_type)) / 4 *
(feed_steps - fast_table.table.size()*2 -
(slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
+ fast_table.pixeltime_sum() * 2 + slow_table.pixeltime_sum();
slow_time =
(scan_exposure_time * scan_yres) / dev->motor.base_ydpi *
(feed_steps - (slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type)))
+ slow_table.pixeltime_sum();
use_fast_fed = fast_time < slow_time;
}
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
if (use_fast_fed) {
feedl = feed_steps - fast_table.table.size() * 2 -
(slow_table.table.size() >> static_cast<unsigned>(motor_profile.step_type));
} else if ((feed_steps << static_cast<unsigned>(motor_profile.step_type)) < slow_table.table.size()) {
if ((feed_steps << static_cast<unsigned>(motor_profile.step_type)) < slow_table.table.size()) {
feedl = 0;
} else {
feedl = (feed_steps << static_cast<unsigned>(motor_profile.step_type)) - slow_table.table.size();
}
DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed");
reg->set8(0x3d, (feedl >> 16) & 0xf);
reg->set8(0x3e, (feedl >> 8) & 0xff);
@@ -800,9 +716,6 @@ static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor
reg->find_reg(0x02).value &= ~REG_0x02_MTRREV;
}
if (use_fast_fed)
reg->find_reg(0x02).value |= 0x08;
else
reg->find_reg(0x02).value &= ~0x08;
if (has_flag(flags, ScanFlag::AUTO_GO_HOME))
@@ -876,7 +789,6 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
const ScanSession& session)
{
DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time);
std::uint16_t expavg, expr, expb, expg;
dev->cmd_set->set_fe(dev, sensor, AFE_SET);
@@ -933,11 +845,7 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
/* AFEMOD should depend on FESET, and we should set these
* bits separately */
reg->find_reg(0x04).value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD);
if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
reg->find_reg(0x04).value |= 0x10; /* no filter */
}
else if (session.params.channels == 1)
{
if (session.params.channels == 1) {
switch (session.params.color_filter)
{
case ColorFilter::RED:
@@ -967,23 +875,6 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
/* CIS scanners can do true gray by setting LEDADD */
reg->find_reg(0x87).value &= ~REG_0x87_LEDADD;
if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) {
reg->find_reg(0x87).value |= REG_0x87_LEDADD;
expr = reg->get16(REG_EXPR);
expg = reg->get16(REG_EXPG);
expb = reg->get16(REG_EXPB);
/* use minimal exposure for best image quality */
expavg = expg;
if (expr < expg)
expavg = expr;
if (expb < expavg)
expavg = expb;
dev->reg.set16(REG_EXPR, expavg);
dev->reg.set16(REG_EXPG, expavg);
dev->reg.set16(REG_EXPB, expavg);
}
// enable gamma tables
if (should_enable_gamma(session, sensor)) {
@@ -1003,27 +894,6 @@ static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sens
reg->set8(0x34, sensor.dummy_pixel);
}
static int
gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor)
{
int d,r,g,b,m;
if (!dev->model->is_cis)
return 0;
d = dev->reg.find_reg(0x19).value;
r = sensor.exposure.red;
g = sensor.exposure.green;
b = sensor.exposure.blue;
m = r;
if (m < g)
m = g;
if (m < b)
m = b;
return m + d;
}
/** @brief compute exposure time
* Compute exposure time for the device and the given scan resolution
*/
@@ -1032,9 +902,13 @@ static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor
int start,
int used_pixels)
{
int led_exposure;
led_exposure=gl841_get_led_exposure(dev, sensor);
int led_exposure = 0;
if (dev->model->is_cis) {
unsigned dummy = dev->reg.find_reg(0x19).value;
unsigned max_sensor_exposure = std::max({sensor.exposure.red, sensor.exposure.green,
sensor.exposure.blue});
led_exposure = dummy + max_sensor_exposure;
}
return sanei_genesys_exposure_time2(dev, profile, slope_dpi,
start + used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
led_exposure);
@@ -1126,6 +1000,9 @@ dummy \ scanned lines
dev->total_bytes_read = 0;
dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines;
if (session.use_host_side_gray) {
dev->total_bytes_to_read /= 3;
}
DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read);
}
@@ -1163,19 +1040,6 @@ ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev,
start += dev->settings.tl_x;
start = static_cast<float>((start * dev->settings.xres) / MM_PER_INCH);
// we enable true gray for cis scanners only, and just when doing
// scan since color calibration is OK for this mode
ScanFlag flags = ScanFlag::NONE;
// true gray (led add for cis scanners)
if (dev->model->is_cis && dev->settings.true_gray &&
dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS &&
dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80)
{
// on Lide 80 the LEDADD bit results in only red LED array being lit
flags |= ScanFlag::ENABLE_LEDADD;
}
ScanSession session;
session.params.xres = dev->settings.xres;
session.params.yres = dev->settings.yres;
@@ -1191,7 +1055,7 @@ ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev,
session.params.color_filter = dev->settings.color_filter;
session.params.contrast_adjustment = dev->settings.contrast;
session.params.brightness_adjustment = dev->settings.brightness;
session.params.flags = flags;
session.params.flags = ScanFlag::NONE;
compute_session(dev, session, sensor);
return session;
@@ -1823,14 +1687,10 @@ static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor&
turn++;
} while ((top-bottom)>1 && turn < 100);
// FIXME: don't overwrite the calibrated values
dev->frontend.set_offset(0, 0);
dev->frontend.set_offset(1, 0);
dev->frontend.set_offset(2, 0);
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
dev->frontend.get_offset(0),
dev->frontend.get_offset(1),
dev->frontend.get_offset(2));
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
dev->frontend.get_offset(0),
dev->frontend.get_offset(1),
dev->frontend.get_offset(2));
}
/* this function does the offset calibration by scanning one line of the calibration
+7 -26
View File
@@ -375,25 +375,13 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
unsigned step_multiplier = gl846_get_step_multiplier(reg);
bool use_fast_fed = false;
if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, ScanFlag::FEEDING)) {
use_fast_fed = true;
}
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
reg->set24(REG_LINCNT, scan_lines);
reg->set8(REG_0x02, 0);
sanei_genesys_set_motor_power(*reg, true);
std::uint8_t reg02 = reg->get8(REG_0x02);
if (use_fast_fed) {
reg02 |= REG_0x02_FASTFED;
} else {
reg02 &= ~REG_0x02_FASTFED;
}
reg02 &= ~REG_0x02_FASTFED;
if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
@@ -447,18 +435,11 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
unsigned feedl = feed_steps;
unsigned dist = 0;
if (use_fast_fed) {
feedl <<= static_cast<unsigned>(fast_profile->step_type);
dist = (scan_table.table.size() + 2 * fast_table.table.size());
// TODO read and decode REG_0xAB
dist += (reg->get8(0x5e) & 31);
dist += reg->get8(REG_FEDCNT);
} else {
feedl <<= static_cast<unsigned>(motor_profile.step_type);
dist = scan_table.table.size();
if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
feedl <<= static_cast<unsigned>(motor_profile.step_type);
dist = scan_table.table.size();
if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
// check for overflow
@@ -514,7 +495,7 @@ static void gl846_init_motor_regs_scan(Genesys_Device* dev,
reg->set8(REG_BWDSTEP, min_restep);
std::uint32_t z1, z2;
sanei_genesys_calculate_zmod(use_fast_fed,
sanei_genesys_calculate_zmod(false,
scan_exposure_time * ccdlmt * tgtime,
scan_table.table,
scan_table.table.size(),
+7 -27
View File
@@ -339,25 +339,13 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
unsigned step_multiplier = gl847_get_step_multiplier (reg);
bool use_fast_fed = false;
if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, ScanFlag::FEEDING)) {
use_fast_fed = true;
}
if (has_flag(dev->model->flags, ModelFlag::DISABLE_FAST_FEEDING)) {
use_fast_fed = false;
}
reg->set24(REG_LINCNT, scan_lines);
reg->set8(REG_0x02, 0);
sanei_genesys_set_motor_power(*reg, true);
std::uint8_t reg02 = reg->get8(REG_0x02);
if (use_fast_fed) {
reg02 |= REG_0x02_FASTFED;
} else {
reg02 &= ~REG_0x02_FASTFED;
}
reg02 &= ~REG_0x02_FASTFED;
if (has_flag(flags, ScanFlag::AUTO_GO_HOME)) {
reg02 |= REG_0x02_AGOHOME | REG_0x02_NOTHOME;
@@ -403,19 +391,11 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
// correct move distance by acceleration and deceleration amounts
unsigned feedl = feed_steps;
unsigned dist = 0;
if (use_fast_fed)
{
feedl <<= static_cast<unsigned>(fast_step_type);
dist = (scan_table.table.size() + 2 * fast_table.table.size());
// TODO read and decode REG_0xAB
dist += (reg->get8(0x5e) & 31);
dist += reg->get8(REG_FEDCNT);
} else {
feedl <<= static_cast<unsigned>(motor_profile.step_type);
dist = scan_table.table.size();
if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
feedl <<= static_cast<unsigned>(motor_profile.step_type);
dist = scan_table.table.size();
if (has_flag(flags, ScanFlag::FEEDING)) {
dist *= 2;
}
// check for overflow
@@ -457,7 +437,7 @@ static void gl847_init_motor_regs_scan(Genesys_Device* dev,
reg->set8(REG_BWDSTEP, min_restep);
std::uint32_t z1, z2;
sanei_genesys_calculate_zmod(use_fast_fed,
sanei_genesys_calculate_zmod(false,
scan_exposure_time * ccdlmt * tgtime,
scan_table.table,
scan_table.table.size(),
+74 -5
View File
@@ -304,8 +304,8 @@ bool ImagePipelineNodeInvert::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source,
ColorOrder color_order) :
ImagePipelineNodeMergeMonoLinesToColor::ImagePipelineNodeMergeMonoLinesToColor(
ImagePipelineNode& source, ColorOrder color_order) :
source_(source),
buffer_(source_.get_row_bytes())
{
@@ -314,7 +314,7 @@ ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNo
output_format_ = get_output_format(source_.get_format(), color_order);
}
bool ImagePipelineNodeMergeMonoLines::get_next_row_data(std::uint8_t* out_data)
bool ImagePipelineNodeMergeMonoLinesToColor::get_next_row_data(std::uint8_t* out_data)
{
bool got_data = true;
@@ -341,8 +341,8 @@ bool ImagePipelineNodeMergeMonoLines::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
PixelFormat ImagePipelineNodeMergeMonoLines::get_output_format(PixelFormat input_format,
ColorOrder order)
PixelFormat ImagePipelineNodeMergeMonoLinesToColor::get_output_format(PixelFormat input_format,
ColorOrder order)
{
switch (input_format) {
case PixelFormat::I1: {
@@ -417,6 +417,75 @@ PixelFormat ImagePipelineNodeSplitMonoLines::get_output_format(PixelFormat input
throw SaneException("Unsupported input format %d", static_cast<unsigned>(input_format));
}
ImagePipelineNodeMergeColorToGray::ImagePipelineNodeMergeColorToGray(ImagePipelineNode& source) :
source_(source)
{
output_format_ = get_output_format(source_.get_format());
float red_mult = 0.2125f;
float green_mult = 0.7154f;
float blue_mult = 0.0721f;
switch (get_pixel_format_color_order(source_.get_format())) {
case ColorOrder::RGB: {
ch0_mult_ = red_mult;
ch1_mult_ = green_mult;
ch2_mult_ = blue_mult;
break;
}
case ColorOrder::BGR: {
ch0_mult_ = blue_mult;
ch1_mult_ = green_mult;
ch2_mult_ = red_mult;
break;
}
case ColorOrder::GBR: {
ch0_mult_ = green_mult;
ch1_mult_ = blue_mult;
ch2_mult_ = red_mult;
break;
}
default:
throw SaneException("Unknown color order");
}
temp_buffer_.resize(source_.get_row_bytes());
}
bool ImagePipelineNodeMergeColorToGray::get_next_row_data(std::uint8_t* out_data)
{
auto* src_data = temp_buffer_.data();
bool got_data = source_.get_next_row_data(src_data);
auto src_format = source_.get_format();
for (std::size_t x = 0, width = get_width(); x < width; ++x) {
std::uint16_t ch0 = get_raw_channel_from_row(src_data, x, 0, src_format);
std::uint16_t ch1 = get_raw_channel_from_row(src_data, x, 1, src_format);
std::uint16_t ch2 = get_raw_channel_from_row(src_data, x, 2, src_format);
float mono = ch0 * ch0_mult_ + ch1 * ch1_mult_ + ch2 * ch2_mult_;
set_raw_channel_to_row(out_data, x, 0, static_cast<std::uint16_t>(mono), output_format_);
}
return got_data;
}
PixelFormat ImagePipelineNodeMergeColorToGray::get_output_format(PixelFormat input_format)
{
switch (input_format) {
case PixelFormat::RGB111:
return PixelFormat::I1;
case PixelFormat::RGB888:
case PixelFormat::BGR888:
return PixelFormat::I8;
case PixelFormat::RGB161616:
case PixelFormat::BGR161616:
return PixelFormat::I16;
default: break;
}
throw SaneException("Unsupported format %d", static_cast<unsigned>(input_format));
}
ImagePipelineNodeComponentShiftLines::ImagePipelineNodeComponentShiftLines(
ImagePipelineNode& source, unsigned shift_r, unsigned shift_g, unsigned shift_b) :
source_(source),
+30 -3
View File
@@ -295,11 +295,11 @@ private:
};
// A pipeline node that merges 3 mono lines into a color channel
class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode
class ImagePipelineNodeMergeMonoLinesToColor : public ImagePipelineNode
{
public:
ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source,
ColorOrder color_order);
ImagePipelineNodeMergeMonoLinesToColor(ImagePipelineNode& source,
ColorOrder color_order);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height() / 3; }
@@ -342,6 +342,33 @@ private:
unsigned next_channel_ = 0;
};
// A pipeline node that merges 3 mono lines into a gray channel
class ImagePipelineNodeMergeColorToGray : public ImagePipelineNode
{
public:
ImagePipelineNodeMergeColorToGray(ImagePipelineNode& source);
std::size_t get_width() const override { return source_.get_width(); }
std::size_t get_height() const override { return source_.get_height(); }
PixelFormat get_format() const override { return output_format_; }
bool eof() const override { return source_.eof(); }
bool get_next_row_data(std::uint8_t* out_data) override;
private:
static PixelFormat get_output_format(PixelFormat input_format);
ImagePipelineNode& source_;
PixelFormat output_format_ = PixelFormat::UNKNOWN;
float ch0_mult_ = 0;
float ch1_mult_ = 0;
float ch2_mult_ = 0;
std::vector<std::uint8_t> temp_buffer_;
};
// A pipeline node that shifts colors across lines by the given offsets
class ImagePipelineNodeComponentShiftLines : public ImagePipelineNode
{
+25 -4
View File
@@ -442,7 +442,11 @@ Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession&
}
if (dev->model->is_cis && session.params.channels == 3) {
pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
pipeline.push_node<ImagePipelineNodeMergeMonoLinesToColor>(dev->model->line_mode_color_order);
}
if (session.use_host_side_gray) {
pipeline.push_node<ImagePipelineNodeMergeColorToGray>();
}
if (pipeline.get_output_format() == PixelFormat::BGR888) {
@@ -540,7 +544,7 @@ Image read_shuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& s
}
if (dev->model->is_cis && session.params.channels == 3) {
pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev->model->line_mode_color_order);
pipeline.push_node<ImagePipelineNodeMergeMonoLinesToColor>(dev->model->line_mode_color_order);
}
if (pipeline.get_output_format() == PixelFormat::BGR888) {
@@ -954,6 +958,14 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
s.output_startx = static_cast<unsigned>(
static_cast<int>(s.params.startx) + sensor.output_pixel_offset);
if (has_flag(dev->model->flags, ModelFlag::HOST_SIDE_GRAY) && s.params.channels == 1 &&
s.params.color_filter == ColorFilter::NONE)
{
s.use_host_side_gray = true;
s.params.channels = 3;
s.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
}
s.stagger_x = sensor.stagger_x;
s.stagger_y = sensor.stagger_y;
@@ -1119,7 +1131,8 @@ void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Se
dev->model->asic_type == AsicType::GL845 ||
dev->model->asic_type == AsicType::GL846)
{
s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis && dev->settings.true_gray);
s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis &&
s.params.color_filter == ColorFilter::NONE);
}
s.use_host_side_calib = sensor.use_host_side_calib;
@@ -1217,7 +1230,7 @@ ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSes
}
if (dev.model->is_cis && session.params.channels == 3) {
pipeline.push_node<ImagePipelineNodeMergeMonoLines>(dev.model->line_mode_color_order);
pipeline.push_node<ImagePipelineNodeMergeMonoLinesToColor>(dev.model->line_mode_color_order);
if (log_image_data) {
pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_4_after_merge_mono.tiff");
@@ -1279,6 +1292,14 @@ ImagePipelineStack build_image_pipeline(const Genesys_Device& dev, const ScanSes
}
}
if (session.use_host_side_gray) {
pipeline.push_node<ImagePipelineNodeMergeColorToGray>();
if (log_image_data) {
pipeline.push_node<ImagePipelineNodeDebug>(debug_prefix + "_10_after_nogray.tiff");
}
}
if (pipeline.get_output_width() != session.params.get_requested_pixels()) {
pipeline.push_node<ImagePipelineNodeScaleRows>(session.params.get_requested_pixels());
}
+3 -1
View File
@@ -129,7 +129,8 @@ bool ScanSession::operator==(const ScanSession& other) const
shading_pixel_offset == other.shading_pixel_offset &&
buffer_size_read == other.buffer_size_read &&
enable_ledadd == other.enable_ledadd &&
use_host_side_calib == other.use_host_side_calib;
use_host_side_calib == other.use_host_side_calib &&
use_host_side_gray == other.use_host_side_gray;
}
std::ostream& operator<<(std::ostream& out, const ScanSession& session)
@@ -166,6 +167,7 @@ std::ostream& operator<<(std::ostream& out, const ScanSession& session)
<< " buffer_size_read: " << session.buffer_size_read << '\n'
<< " enable_ledadd: " << session.enable_ledadd << '\n'
<< " use_host_side_calib: " << session.use_host_side_calib << '\n'
<< " use_host_side_gray: " << session.use_host_side_gray << '\n'
<< " params: " << format_indent_braced_list(4, session.params) << '\n'
<< "}";
return out;
+4 -3
View File
@@ -76,9 +76,6 @@ struct Genesys_Settings
ColorFilter color_filter = ColorFilter::NONE;
// true if scan is true gray, false if monochrome scan
int true_gray = 0;
// value for contrast enhancement in the [-100..100] range
int contrast = 0;
@@ -327,6 +324,9 @@ struct ScanSession {
// whether calibration should be performed host-side
bool use_host_side_calib = false;
// whether gray scanning should be performed host-side (scan as color and merge to gray)
bool use_host_side_gray = false;
void assert_computed() const
{
if (!computed) {
@@ -378,6 +378,7 @@ void serialize(Stream& str, ScanSession& x)
serialize(str, x.buffer_size_read);
serialize(str, x.enable_ledadd);
serialize(str, x.use_host_side_calib);
serialize(str, x.use_host_side_gray);
}
std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params);
+3
View File
@@ -191,6 +191,7 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::CANON_LIDE_35;
model.motor_id = MotorId::CANON_LIDE_35;
model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
ModelFlag::HOST_SIDE_GRAY |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
@@ -1110,6 +1111,7 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::CANON_LIDE_35;
model.motor_id = MotorId::CANON_LIDE_60;
model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
ModelFlag::HOST_SIDE_GRAY |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_COPY_SW |
@@ -1165,6 +1167,7 @@ void genesys_init_usb_device_tables()
model.gpio_id = GpioId::CANON_LIDE_80;
model.motor_id = MotorId::CANON_LIDE_80;
model.flags = ModelFlag::DARK_WHITE_CALIBRATION |
ModelFlag::HOST_SIDE_GRAY |
ModelFlag::CUSTOM_GAMMA;
model.buttons = GENESYS_HAS_SCAN_SW |
GENESYS_HAS_FILE_SW |
+4 -4
View File
@@ -471,8 +471,8 @@ void genesys_init_sensor_tables()
sensor.register_dpihw = 1200;
sensor.black_pixels = 87;
sensor.dummy_pixel = 87;
sensor.fau_gain_white_ref = 0;
sensor.gain_white_ref = 0;
sensor.fau_gain_white_ref = 100;
sensor.gain_white_ref = 100;
sensor.exposure = { 0x0400, 0x0400, 0x0400 };
sensor.custom_regs = {
{ 0x16, 0x00 }, { 0x17, 0x02 }, { 0x18, 0x00 }, { 0x19, 0x50 },
@@ -519,8 +519,8 @@ void genesys_init_sensor_tables()
sensor.register_dpihw = 1200;
sensor.black_pixels = 87;
sensor.dummy_pixel = 87;
sensor.fau_gain_white_ref = 0;
sensor.gain_white_ref = 0;
sensor.fau_gain_white_ref = 100;
sensor.gain_white_ref = 100;
sensor.exposure = { 0x0400, 0x0400, 0x0400 };
sensor.custom_regs = {
{ 0x16, 0x00 }, { 0x17, 0x01 }, { 0x18, 0x00 }, { 0x19, 0x50 },
@@ -468,7 +468,7 @@ void test_node_invert_1_bits()
ASSERT_EQ(out_data, expected_data);
}
void test_node_merge_mono_lines()
void test_node_merge_mono_lines_to_color()
{
using Data = std::vector<std::uint8_t>;
@@ -481,7 +481,7 @@ void test_node_merge_mono_lines()
ImagePipelineStack stack;
stack.push_first_node<ImagePipelineNodeArraySource>(8, 3, PixelFormat::I8,
std::move(in_data));
stack.push_node<ImagePipelineNodeMergeMonoLines>(ColorOrder::RGB);
stack.push_node<ImagePipelineNodeMergeMonoLinesToColor>(ColorOrder::RGB);
ASSERT_EQ(stack.get_output_width(), 8u);
ASSERT_EQ(stack.get_output_height(), 1u);
@@ -500,6 +500,37 @@ void test_node_merge_mono_lines()
ASSERT_EQ(out_data, expected_data);
}
void test_node_merge_color_to_gray()
{
using Data = std::vector<std::uint8_t>;
Data in_data = {
0x10, 0x20, 0x30, 0x11, 0x21, 0x31,
0x12, 0x22, 0x32, 0x13, 0x23, 0x33,
0x14, 0x24, 0x34, 0x15, 0x25, 0x35,
0x16, 0x26, 0x36, 0x17, 0x27, 0x37,
};
ImagePipelineStack stack;
stack.push_first_node<ImagePipelineNodeArraySource>(8, 1, PixelFormat::RGB888,
std::move(in_data));
stack.push_node<ImagePipelineNodeMergeColorToGray>();
ASSERT_EQ(stack.get_output_width(), 8u);
ASSERT_EQ(stack.get_output_height(), 1u);
ASSERT_EQ(stack.get_output_row_bytes(), 8u);
ASSERT_EQ(stack.get_output_format(), PixelFormat::I8);
auto out_data = stack.get_all_data();
Data expected_data = {
0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24
};
ASSERT_EQ(out_data, expected_data);
}
void test_node_split_mono_lines()
{
using Data = std::vector<std::uint8_t>;
@@ -937,7 +968,8 @@ void test_image_pipeline()
test_node_invert_16_bits();
test_node_invert_8_bits();
test_node_invert_1_bits();
test_node_merge_mono_lines();
test_node_merge_mono_lines_to_color();
test_node_merge_color_to_gray();
test_node_split_mono_lines();
test_node_component_shift_lines();
test_node_pixel_shift_columns_no_switch();