- shading calibration rework for gl646 based scanners

merge-requests/1/head
Stéphane Voltz 2009-04-14 05:15:29 +00:00
rodzic 18e88c02a7
commit a7a759b896
4 zmienionych plików z 426 dodań i 392 usunięć

Wyświetl plik

@ -1,3 +1,7 @@
2009-04-14 Stéphane Voltz <stef.dev@free.fr>
* backend/genesys.c backend/genesys_devices.c backend/genesys_gl646.c:
shading calibration rework for GL646 based scanners
2009-04-13 m. allan noah <kitno455 a t gmail d o t com>
* tools/sane-desc.c: fix double summing of untested column

Wyświetl plik

@ -52,7 +52,7 @@
#include "../include/sane/config.h"
#define BUILD 10
#define BUILD 11
#include <errno.h>
#include <string.h>
@ -188,6 +188,7 @@ sanei_genesys_write_pnm_file (char *filename, uint8_t * data, int depth,
int channels, int pixels_per_line, int lines)
{
FILE *out;
int count;
DBG (DBG_info,
"sanei_genesys_write_pnm_file: depth=%d, channels=%d, ppl=%d, lines=%d\n",
@ -205,7 +206,6 @@ sanei_genesys_write_pnm_file (char *filename, uint8_t * data, int depth,
pixels_per_line, lines, (int) pow (2, depth) - 1);
if (channels == 3)
{
int count = 0;
for (count = 0; count < (pixels_per_line * lines * 3); count++)
{
if (depth == 16)
@ -217,7 +217,6 @@ sanei_genesys_write_pnm_file (char *filename, uint8_t * data, int depth,
}
else
{
int count = 0;
for (count = 0; count < (pixels_per_line * lines); count++)
{
if (depth == 8)
@ -1308,7 +1307,7 @@ genesys_send_offset_and_shading (Genesys_Device * dev, uint8_t * data,
dpihw = sanei_genesys_read_reg_from_set (dev->reg, 0x05) >> 6;
if (dev->settings.scan_mode < 2 && dev->model->ccd_type != CCD_HP2300 && dev->model->ccd_type != CCD_HP2400 && dev->model->ccd_type != CCD_5345) /* lineart, halftone */
if (dev->settings.scan_mode < 2 && dev->model->ccd_type != CCD_HP2300 && dev->model->ccd_type != CCD_HP2400 && dev->model->ccd_type != CCD_HP3670 && dev->model->ccd_type != CCD_5345) /* lineart, halftone */
{
if (dpihw == 0) /* 600 dpi */
start_address = 0x02a00;
@ -2310,40 +2309,25 @@ genesys_dark_shading_calibration (Genesys_Device * dev)
status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE);
if (status != SANE_STATUS_GOOD)
{
free (calibration_data);
DBG (DBG_error,
"genesys_dark_shading_calibration: Failed to end scan: %s\n",
sane_strstatus (status));
return status;
}
dev->model->cmd_set->set_motor_power (dev->calib_reg, SANE_FALSE);
dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE);
status =
dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg,
dev->model->cmd_set->
bulk_full_size ());
if (status != SANE_STATUS_GOOD)
{
free (calibration_data);
DBG (DBG_error,
"genesys_dark_shading_calibration: Failed to bulk write registers: %s\n",
sane_strstatus (status));
return status;
}
if (DBG_LEVEL >= DBG_data)
sanei_genesys_write_pnm_file ("black_shading.pnm", calibration_data, 16,
channels, pixels_per_line,
dev->model->shading_lines);
genesys_average_data (dev->dark_average_data, calibration_data,
dev->model->shading_lines,
pixels_per_line * channels);
if (DBG_LEVEL >= DBG_data)
{
sanei_genesys_write_pnm_file ("black_shading.pnm", calibration_data, 16,
channels, pixels_per_line,
dev->model->shading_lines);
sanei_genesys_write_pnm_file ("black_average.pnm", dev->dark_average_data,
16, channels, pixels_per_line, 1);
}
free (calibration_data);
@ -2468,6 +2452,8 @@ genesys_white_shading_calibration (Genesys_Device * dev)
pixels_per_line =
(genesys_pixels_per_line (dev->calib_reg)
* genesys_dpiset (dev->calib_reg)) / dev->sensor.optical_res;
/* XXX STEF XXX */
pixels_per_line = dev->calib_pixels;
if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */
channels = 3;
@ -2497,7 +2483,7 @@ genesys_white_shading_calibration (Genesys_Device * dev)
/* turn on motor and lamp power */
dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE);
dev->model->cmd_set->set_motor_power (dev->calib_reg, SANE_FALSE); /* XXX STEF */
dev->model->cmd_set->set_motor_power (dev->calib_reg, SANE_TRUE);
status =
dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg,
@ -2595,7 +2581,6 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev)
DBG (DBG_proc, "genesys_black_white_shading_calibration (lines = %d)\n",
dev->model->shading_lines);
pixels_per_line =
(genesys_pixels_per_line (dev->calib_reg)
* genesys_dpiset (dev->calib_reg)) / dev->sensor.optical_res;
@ -2641,7 +2626,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev)
/* turn on motor and lamp power */
dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE);
dev->model->cmd_set->set_motor_power (dev->calib_reg, SANE_TRUE);
dev->model->cmd_set->set_motor_power (dev->calib_reg, SANE_FALSE);
status =
dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg,
@ -2772,6 +2757,163 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev)
return SANE_STATUS_GOOD;
}
static unsigned int
compute_coefficient (unsigned int coeff,
unsigned int target_code, unsigned int val)
{
if (val <= 0)
return 65535;
val = (coeff * target_code) / val;
if (val > 65535)
val = 65535;
return val;
}
/**
* Computes shading coefficient using formula in data sheet. 16bit data values
* manipulated here are little endian.
* @param dev scanner's device
* @shading_data memory area where to store the computed shading coefficients
* @param pixels_per_line number of pixels per line
* @param channels number of color channels (actually 1 or 3)
* @param avgpixels number of pixels to average
* @param offset shading coefficients left offset
* @param coeff 4000h or 2000h depending on fast scan mode or not
*/
static void
compute_coefficients (Genesys_Device * dev,
uint8_t * shading_data,
unsigned int pixels_per_line,
unsigned int channels,
unsigned int avgpixels,
unsigned int offset,
unsigned int coeff, unsigned int target_code)
{
uint8_t *ptr; /*contain 16bit words in little endian */
unsigned int x, j;
unsigned int val, dk;
for (x = 0; x < pixels_per_line - offset - avgpixels - 1; x += avgpixels)
{
/* dark data */
ptr = shading_data + (x + offset) * 2 * 2 * 3;
dk = 0;
for (j = 0; j < avgpixels; j++)
{
dk += dev->dark_average_data[(x + j) * 2 * channels];
dk += 256 * dev->dark_average_data[(x + j) * 2 * channels + 1];
}
dk /= j;
for (j = 0; j < avgpixels; j++)
{
ptr[0 + j * 2 * 2 * 3] = dk & 255;
ptr[1 + j * 2 * 2 * 3] = dk / 256;
}
if (channels > 1)
{
dk = 0;
for (j = 0; j < avgpixels; j++)
{
dk += dev->dark_average_data[(x + j) * 2 * channels + 2];
dk += 256 * dev->dark_average_data[(x + j) * 2 * channels + 3];
}
dk /= j;
for (j = 0; j < avgpixels; j++)
{
ptr[4 + j * 2 * 2 * 3] = dk & 255;
ptr[5 + j * 2 * 2 * 3] = dk / 256;
}
dk = 0;
for (j = 0; j < avgpixels; j++)
{
dk += dev->dark_average_data[(x + j) * 2 * channels + 4];
dk += 256 * dev->dark_average_data[(x + j) * 2 * channels + 5];
}
dk /= j;
for (j = 0; j < avgpixels; j++)
{
ptr[8 + j * 2 * 2 * 3] = dk & 255;
ptr[9 + j * 2 * 2 * 3] = dk / 256;
}
}
else
{
for (j = 0; j < avgpixels; j++)
{
ptr[4 + j * 2 * 2 * 3] = ptr[0];
ptr[5 + j * 2 * 2 * 3] = ptr[1];
ptr[8 + j * 2 * 2 * 3] = ptr[0];
ptr[9 + j * 2 * 2 * 3] = ptr[1];
}
}
/* white data */
/* red channel */
val = 0;
for (j = 0; j < avgpixels; j++)
{
val += 256 * dev->white_average_data[(x + j) * 2 * channels + 1];
val += dev->white_average_data[(x + j) * 2 * channels];
}
val /= j;
val -= (256 * ptr[1] + ptr[0]);
val = compute_coefficient (coeff, target_code, val);
for (j = 0; j < avgpixels; j++)
{
ptr[2 + j * 2 * 2 * 3] = val & 0xff;
ptr[3 + j * 2 * 2 * 3] = val / 256;
}
if (channels > 1)
{
/* green */
val = 0;
for (j = 0; j < avgpixels; j++)
{
val +=
256 * dev->white_average_data[(x + j) * 2 * channels + 3];
val += dev->white_average_data[(x + j) * 2 * channels + 2];
}
val /= j;
val -= (256 * ptr[5] + ptr[4]);
val = compute_coefficient (coeff, target_code, val);
for (j = 0; j < avgpixels; j++)
{
ptr[6 + j * 2 * 2 * 3] = val & 0xff;
ptr[7 + j * 2 * 2 * 3] = val / 256;
}
/* blue */
val = 0;
for (j = 0; j < avgpixels; j++)
{
val +=
256 * dev->white_average_data[(x + j) * 2 * channels + 5];
val += dev->white_average_data[(x + j) * 2 * channels + 4];
}
val /= j;
val -= (256 * ptr[9] + ptr[8]);
val = compute_coefficient (coeff, target_code, val);
for (j = 0; j < avgpixels; j++)
{
ptr[10 + j * 2 * 2 * 3] = val & 255;
ptr[11 + j * 2 * 2 * 3] = val / 256;
}
}
else
{
for (j = 0; j < avgpixels; j++)
{
ptr[6 + j * 2 * 2 * 3] = val & 255;
ptr[7 + j * 2 * 2 * 3] = val / 256;
ptr[10 + j * 2 * 2 * 3] = val & 255;
ptr[11 + j * 2 * 2 * 3] = val / 256;
}
}
}
}
static SANE_Status
genesys_send_shading_coefficient (Genesys_Device * dev)
@ -2780,7 +2922,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
uint16_t pixels_per_line;
uint8_t *shading_data; /*contains 16bit words in little endian */
uint8_t channels;
int x, j, o;
unsigned int x, j, o;
unsigned int i, res;
unsigned int coeff, target_code, val, avgpixels, dk, words_per_color = 0;
unsigned int target_dark, target_bright, br;
@ -2831,147 +2973,42 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
coeff = 0x4000;
else
coeff = 0x2000;
switch (dev->model->ccd_type)
{
case CCD_5345:
/* from the logs, we can see that the first 2 coefficients are zeroed,
which surely means that coeff depends in a way or another on the 2 previous
pixel columns */
/* depends upon R06 shading gain */
target_code = 0xFA00;
target_code = 0xfa00;
memset (shading_data, 0x00, pixels_per_line * 4 * channels);
/* todo: if GAIN4, shading data is 'chunky', while it is 'line' when
GAIN4 is reset */
for (x = 2; x < pixels_per_line; x++)
{
/* dark data */
shading_data[x * 2 * 2 * 3] =
dev->dark_average_data[x * 2 * channels];
shading_data[x * 2 * 2 * 3 + 1] =
dev->dark_average_data[x * 2 * channels + 1];
if (channels > 1)
{
shading_data[x * 2 * 2 * 3 + 4] =
dev->dark_average_data[x * 2 * channels + 2];
shading_data[x * 2 * 2 * 3 + 5] =
dev->dark_average_data[x * 2 * channels + 3];
shading_data[x * 2 * 2 * 3 + 8] =
dev->dark_average_data[x * 2 * channels + 4];
shading_data[x * 2 * 2 * 3 + 9] =
dev->dark_average_data[x * 2 * channels + 5];
}
else
{
shading_data[x * 2 * 2 * 3 + 4] =
dev->dark_average_data[x * 2 * channels];
shading_data[x * 2 * 2 * 3 + 5] =
dev->dark_average_data[x * 2 * channels + 1];
shading_data[x * 2 * 2 * 3 + 8] =
dev->dark_average_data[x * 2 * channels];
shading_data[x * 2 * 2 * 3 + 9] =
dev->dark_average_data[x * 2 * channels + 1];
}
/* white data */
/* red channel */
val = 0;
val +=
256 * dev->white_average_data[(x - 2) * 2 * channels + 1] +
dev->white_average_data[(x - 2) * 2 * channels];
val -=
(256 * dev->dark_average_data[(x - 2) * 2 * channels + 1] +
dev->dark_average_data[(x - 2) * 2 * channels]);
val +=
256 * dev->white_average_data[(x - 1) * 2 * channels + 1] +
dev->white_average_data[(x - 1) * 2 * channels];
val -=
(256 * dev->dark_average_data[(x - 1) * 2 * channels + 1] +
dev->dark_average_data[(x - 1) * 2 * channels]);
val +=
256 * dev->white_average_data[(x) * 2 * channels + 1] +
dev->white_average_data[(x) * 2 * channels];
val -=
(256 * dev->dark_average_data[(x) * 2 * channels + 1] +
dev->dark_average_data[(x) * 2 * channels]);
val /= 3;
if ((65535 * val) / coeff > target_code)
val = (coeff * target_code) / val;
else
val = 65535;
shading_data[x * 2 * 2 * 3 + 2] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 3] = val >> 8;
if (channels > 1)
{
/* green */
val = 0;
val +=
256 * dev->white_average_data[(x - 2) * 2 * channels + 3] +
dev->white_average_data[(x - 2) * 2 * channels + 2];
val -=
(256 * dev->dark_average_data[(x - 2) * 2 * channels + 3] +
dev->dark_average_data[(x - 2) * 2 * channels + 2]);
val +=
256 * dev->white_average_data[(x - 1) * 2 * channels + 3] +
dev->white_average_data[(x - 1) * 2 * channels + 2];
val -=
(256 * dev->dark_average_data[(x - 1) * 2 * channels + 3] +
dev->dark_average_data[(x - 1) * 2 * channels + 2]);
val +=
256 * dev->white_average_data[(x) * 2 * channels + 3] +
dev->white_average_data[(x) * 2 * channels + 2];
val -=
(256 * dev->dark_average_data[(x) * 2 * channels + 3] +
dev->dark_average_data[(x) * 2 * channels + 2]);
val /= 3;
if ((65535 * val) / coeff > target_code)
val = (coeff * target_code) / val;
else
val = 65535;
shading_data[x * 2 * 2 * 3 + 6] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 7] = val >> 8;
/* blue */
val = 0;
val +=
256 * dev->white_average_data[(x) * 2 * channels + 5] +
dev->white_average_data[(x) * 2 * channels + 4];
val -=
(256 * dev->dark_average_data[(x) * 2 * channels + 5] +
dev->dark_average_data[(x) * 2 * channels + 4]);
val +=
256 * dev->white_average_data[(x) * 2 * channels + 5] +
dev->white_average_data[(x) * 2 * channels + 4];
val -=
(256 * dev->dark_average_data[(x) * 2 * channels + 5] +
dev->dark_average_data[(x) * 2 * channels + 4]);
val +=
256 * dev->white_average_data[(x) * 2 * channels + 5] +
dev->white_average_data[(x) * 2 * channels + 4];
val -=
(256 * dev->dark_average_data[(x) * 2 * channels + 5] +
dev->dark_average_data[(x) * 2 * channels + 4]);
val /= 3;
if ((65535 * val) / coeff > target_code)
val = (coeff * target_code) / val;
else
val = 65535;
shading_data[x * 2 * 2 * 3 + 10] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 11] = val >> 8;
}
else
{
shading_data[x * 2 * 2 * 3 + 6] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 7] = val >> 8;
shading_data[x * 2 * 2 * 3 + 10] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 11] = val >> 8;
}
}
o=2;
avgpixels = 1;
compute_coefficients(dev,
shading_data,
pixels_per_line,
channels,
avgpixels,
o,
coeff,
target_code);
break;
case CCD_HP2300:
case CCD_HP2400:
case CCD_HP3670:
target_code = 0xfa00;
memset (shading_data, 0x00, pixels_per_line * 4 * channels);
o = 2; /* when ~AVEENB, o=3 if AVEENB ? */
if(dev->settings.xres<=150)
avgpixels = 2;
else
avgpixels = 1;
/* TODO: if FASTMODE, shading data is 'color component line by line' */
compute_coefficients(dev,
shading_data,
pixels_per_line,
channels,
avgpixels,
o,
coeff,
target_code);
break;
case CCD_CANONLIDE35:
target_bright = 0xfa00;
@ -3046,21 +3083,25 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
for (i = 0; i < avgpixels; i++)
{
/* dark data */
dk += (dev->dark_average_data[(x + i + pixels_per_line * j) * 2]
| (dev->
dark_average_data[(x + i + pixels_per_line * j) * 2 +
1] << 8));
dk +=
(dev->dark_average_data[(x + i +
pixels_per_line * j) *
2] |
(dev->dark_average_data
[(x + i + pixels_per_line * j) * 2 + 1] << 8));
/* white data */
br += (dev->white_average_data[(x + i + pixels_per_line * j) * 2]
| (dev->
white_average_data[(x + i + pixels_per_line * j) * 2 +
1] << 8));
br +=
(dev->white_average_data[(x + i +
pixels_per_line * j) *
2] |
(dev->white_average_data
[(x + i + pixels_per_line * j) * 2 + 1] << 8));
}
br /= avgpixels;
dk /= avgpixels;
if (br * target_dark > dk * target_bright)
val = 0;
else if (dk * target_bright - br * target_dark >
@ -3104,8 +3145,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
{
shading_data[(x + o + i) * 2 * 2 +
words_per_color * j] =
shading_data[(x + o + i) * 2 * 2 +
words_per_color * 0];
shading_data[(x + o + i) * 2 * 2 + words_per_color * 0];
shading_data[(x + o + i) * 2 * 2 +
words_per_color * j + 1] =
shading_data[(x + o + i) * 2 * 2 +
@ -3134,134 +3174,11 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
}
*/
break;
case CCD_HP2300:
case CCD_HP2400:
default:
target_code = 0xFA00;
for (x = 6; x < pixels_per_line; x++)
{
/* dark data */
val = 0;
for (i = 0; i < 7; i++)
{
val += dev->dark_average_data[(x - i) * 2 * channels];
val += 256 * dev->dark_average_data[(x - i) * 2 * channels + 1];
}
val /= i;
shading_data[x * 2 * 2 * 3] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 1] = val >> 8;
if (channels > 1)
{
val = 0;
for (i = 0; i < 7; i++)
{
val += dev->dark_average_data[(x - i) * 2 * channels + 2];
val +=
256 * dev->dark_average_data[(x - i) * 2 * channels + 3];
}
val /= i;
shading_data[x * 2 * 2 * 3 + 4] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 5] = val >> 8;
val = 0;
for (i = 0; i < 7; i++)
{
val += dev->dark_average_data[(x - i) * 2 * channels + 4];
val +=
256 * dev->dark_average_data[(x - i) * 2 * channels + 5];
}
val /= i;
shading_data[x * 2 * 2 * 3 + 8] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 9] = val >> 8;
}
else
{
shading_data[x * 2 * 2 * 3 + 4] = shading_data[x * 2 * 2 * 3];
shading_data[x * 2 * 2 * 3 + 5] =
shading_data[x * 2 * 2 * 3 + 1];
shading_data[x * 2 * 2 * 3 + 8] = shading_data[x * 2 * 2 * 3];
shading_data[x * 2 * 2 * 3 + 9] =
shading_data[x * 2 * 2 * 3 + 1];
}
/* white data */
val = 0;
/* average on 7 rows */
for (i = 0; i < 7; i++)
{
val +=
256 * dev->white_average_data[(x - i) * 2 * channels + 1] +
dev->white_average_data[(x - i) * 2 * channels];
val -=
(256 * dev->dark_average_data[(x - i) * 2 * channels + 1] +
dev->dark_average_data[(x - i) * 2 * channels]);
}
val /= i;
if ((65535 * val) / coeff > target_code)
val = (coeff * target_code) / val;
else
val = 65535;
shading_data[x * 2 * 2 * 3 + 2] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 3] = val >> 8;
if (channels > 1)
{
/* green */
/* average on 7 rows */
val = 0;
for (i = 0; i < 7; i++)
{
val +=
256 * dev->white_average_data[(x - i) * 2 * channels +
3] +
dev->white_average_data[(x - i) * 2 * channels + 2];
val -=
(256 *
dev->dark_average_data[(x - i) * 2 * channels + 3] +
dev->dark_average_data[(x - i) * 2 * channels + 2]);
}
val /= i;
if ((65535 * val) / coeff > target_code)
val = (coeff * target_code) / val;
else
val = 65535;
shading_data[x * 2 * 2 * 3 + 6] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 7] = val >> 8;
/* blue */
/* average on 7 rows */
val = 0;
for (i = 0; i < 7; i++)
{
val +=
256 * dev->white_average_data[(x - i) * 2 * channels +
5] +
dev->white_average_data[(x - i) * 2 * channels + 4];
val -=
(256 *
dev->dark_average_data[(x - i) * 2 * channels + 5] +
dev->dark_average_data[(x - i) * 2 * channels + 4]);
}
val /= i;
if ((65535 * val) / coeff > target_code)
val = (coeff * target_code) / val;
else
val = 65535;
shading_data[x * 2 * 2 * 3 + 10] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 11] = val >> 8;
}
else
{
shading_data[x * 2 * 2 * 3 + 6] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 7] = val >> 8;
shading_data[x * 2 * 2 * 3 + 10] = val & 0xff;
shading_data[x * 2 * 2 * 3 + 11] = val >> 8;
}
}
DBG (DBG_error,
"genesys_send_shading_coefficient: sensor %d not supported\n",
dev->model->ccd_type);
return SANE_STATUS_UNSUPPORTED;
break;
}
@ -3353,7 +3270,7 @@ genesys_restore_calibration (Genesys_Device * dev)
static SANE_Status
genesys_save_calibration (Genesys_Device * dev)
{
SANE_Status status;
SANE_Status status=SANE_STATUS_UNSUPPORTED;
Genesys_Calibration_Cache *cache;
uint8_t *tmp;
@ -3362,22 +3279,17 @@ genesys_save_calibration (Genesys_Device * dev)
if (!dev->model->cmd_set->is_compatible_calibration)
return SANE_STATUS_UNSUPPORTED;
for(cache = dev->calibration_cache; cache; cache = cache->next)
for(cache = dev->calibration_cache; cache && status==SANE_STATUS_UNSUPPORTED; cache = cache->next)
{
status = dev->model->cmd_set->is_compatible_calibration(dev, cache,
SANE_TRUE);
if (status == SANE_STATUS_UNSUPPORTED)
{
continue;
}
else if (status != SANE_STATUS_GOOD)
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error,
"genesys_save_calibration: fail while checking compatibility: %s\n",
sane_strstatus (status));
return status;
}
break;
}
if(cache)
@ -3600,9 +3512,13 @@ genesys_flatbed_calibration (Genesys_Device * dev)
return status;
}
/* GL646 scanners set up calib_pixels in init_regs_for_shading */
if (dev->model->asic_type != GENESYS_GL646)
{
dev->calib_pixels =
(genesys_pixels_per_line (dev->calib_reg)
* genesys_dpiset (dev->calib_reg)) / dev->sensor.optical_res;
}
if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION)
{
@ -3872,9 +3788,10 @@ genesys_start_scan (Genesys_Device * dev)
RIE (genesys_warmup_lamp (dev));
}
/* set top left x and y values if flatbed scanners */
/* set top left x and y values by scanning the internals if flatbed scanners */
if (dev->model->is_sheetfed == SANE_FALSE)
{
/* do the geometry detection only once */
if ((dev->model->flags & GENESYS_FLAG_SEARCH_START)
&& (dev->model->y_offset_calib == 0))
{
@ -5299,7 +5216,7 @@ init_options (Genesys_Scanner * s)
s->opt[OPT_CALIBRATE].type = SANE_TYPE_BUTTON;
s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE;
if (model->buttons & GENESYS_HAS_CALIBRATE)
s->opt[OPT_CALIBRATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | SANE_CAP_AUTOMATIC;
s->opt[OPT_CALIBRATE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | SANE_CAP_AUTOMATIC;
else
s->opt[OPT_CALIBRATE].cap = SANE_CAP_INACTIVE;
s->val[OPT_CALIBRATE].b = 0;

Wyświetl plik

@ -104,8 +104,8 @@ static Genesys_Frontend Wolfson[] = {
, /* 6: CANONLIDE35 */
{DAC_AD_XP200,{0x58, 0x00, 0x00, 0x00} /* TODO create an AnalogDevice struct */
, {0x00, 0x00, 0x00}
, {0x06, 0x00, 0x00}
, {0x0c, 0x00, 0x00}
, {0x0a, 0x00, 0x00} /* offset */
, {0x20, 0x00, 0x00} /* gain */
, {0x00, 0x00, 0x00}
}
,
@ -830,7 +830,7 @@ static Genesys_Model hp2300c_model = {
GPO_HP2300,
MOTOR_HP2300,
GENESYS_FLAG_14BIT_GAMMA
/* | GENESYS_FLAG_NO_CALIBRATION */
| GENESYS_FLAG_LAZY_INIT
| GENESYS_FLAG_SEARCH_START
| GENESYS_FLAG_DARK_CALIBRATION
| GENESYS_FLAG_OFFSET_CALIBRATION
@ -885,6 +885,7 @@ Genesys_Model hp2400c_model = {
GPO_HP2400,
MOTOR_HP2400,
GENESYS_FLAG_UNTESTED /* not fully working yet */
| GENESYS_FLAG_LAZY_INIT
| GENESYS_FLAG_14BIT_GAMMA
| GENESYS_FLAG_DARK_CALIBRATION
| GENESYS_FLAG_OFFSET_CALIBRATION
@ -943,7 +944,7 @@ Genesys_Model visioneer_xp200_model = {
| GENESYS_FLAG_CUSTOM_GAMMA
| GENESYS_FLAG_SKIP_WARMUP
| GENESYS_FLAG_NO_CALIBRATION,
GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE,
GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW, /* | GENESYS_HAS_CALIBRATE, */
20,
132
};
@ -992,6 +993,7 @@ static Genesys_Model hp3670c_model = {
MOTOR_HP3670,
GENESYS_FLAG_14BIT_GAMMA
| GENESYS_FLAG_SEARCH_START
| GENESYS_FLAG_SKIP_WARMUP
| GENESYS_FLAG_DARK_CALIBRATION
| GENESYS_FLAG_OFFSET_CALIBRATION
| GENESYS_FLAG_CUSTOM_GAMMA,

Wyświetl plik

@ -1278,9 +1278,9 @@ gl646_setup_registers (Genesys_Device * dev,
/* vfinal=(exposure/(1200/dpi))/step_type */
/* DBG (DBG_info, "XXX STEF XXX vfinal=%d, vend1=%d\n",
(sensor->exposure * sensor->xdpi) / ((1 << motor->steptype) *
dev->sensor.optical_res),
motor->vend1);*/
(sensor->exposure * sensor->xdpi) / ((1 << motor->steptype) *
dev->sensor.optical_res),
motor->vend1); */
/* half_ccd if manual clock programming or dpi is half dpiset */
half_ccd = sensor->half_ccd;
@ -1353,9 +1353,9 @@ gl646_setup_registers (Genesys_Device * dev,
/* allow moving when buffer full by default */
if (dev->model->is_sheetfed == SANE_FALSE)
dev->reg[reg_0x02].value &= ~REG02_ACDCDIS;
dev->reg[reg_0x02].value &= ~REG02_ACDCDIS;
else
dev->reg[reg_0x02].value |= REG02_ACDCDIS;
dev->reg[reg_0x02].value |= REG02_ACDCDIS;
/* setup motor power */
regs[reg_0x02].value |= REG02_MTRPWR;
@ -1393,6 +1393,10 @@ gl646_setup_registers (Genesys_Device * dev,
regs[reg_0x02].value |= REG02_AGOHOME;
}
/* R03 */
regs[reg_0x03].value &= ~REG03_AVEENB;
/* regs[reg_0x03].value |= REG03_AVEENB; */
/* R04 */
if (depth > 8)
{
@ -1619,8 +1623,15 @@ gl646_setup_registers (Genesys_Device * dev,
gl646_set_double_reg (regs, REG_Z2MOD, z2);
regs[reg_0x6b].value = motor->steps2;
regs[reg_0x6c].value =
(regs[reg_0x6c].
value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) & 0x07);
(regs[reg_0x6c].value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16)
& 0x07);
/* the 3670 seems to behave differently regarding GPIO */
/* TODO to be added in the sensor setting struct ?? */
if (dev->model->ccd_type==CCD_HP3670)
{
dev->reg[reg_0x66].value = 0;
}
RIE (write_control (dev, xresolution));
@ -1986,6 +1997,7 @@ gl646_init_regs (Genesys_Device * dev)
dev->reg[reg_0x20].value = 0x20;
break;
case CCD_HP2400:
case CCD_HP3670:
dev->reg[reg_0x1e].value = 0x80;
dev->reg[reg_0x1f].value = 0x10;
dev->reg[reg_0x20].value = 0x20;
@ -2064,6 +2076,11 @@ gl646_init_regs (Genesys_Device * dev)
dev->reg[reg_0x6b].value = 0x08; /* table two steps number for acc/dec */
dev->reg[reg_0x6d].value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */
break;
case MOTOR_HP3670:
dev->reg[reg_0x6a].value = 0x41; /* table two steps number for acc/dec */
dev->reg[reg_0x6b].value = 0xc8; /* table two steps number for acc/dec */
dev->reg[reg_0x6d].value = 0x7f;
break;
default:
dev->reg[reg_0x6a].value = 0x40; /* table two fast moving step type, PWM duty for table two */
dev->reg[reg_0x6b].value = 0xff; /* table two steps number for acc/dec */
@ -2238,30 +2255,34 @@ gl646_set_fe (Genesys_Device * dev, uint8_t set)
{
status = sanei_genesys_fe_write_data (dev, 0x01, 0x02);
if (status != SANE_STATUS_GOOD)
DBG (DBG_error, "gl646_set_fe: writing data failed: %s\n",
sane_strstatus (status));
{
DBG (DBG_error, "gl646_set_fe: writing data failed: %s\n",
sane_strstatus (status));
}
return status;
}
/* here starts AFE_SET */
/* TODO : base this test on cfg reg3 or a CCD family flag to be created */
/*if (dev->model->ccd_type != CCD_HP2300
&& dev->model->ccd_type != CCD_HP2400) */
{
status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error, "gl646_set_fe: writing reg0 failed: %s\n",
sane_strstatus (status));
return status;
}
status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error, "gl646_set_fe: writing reg2 failed: %s\n",
sane_strstatus (status));
return status;
}
}
/* if (dev->model->ccd_type != CCD_HP2300
&& dev->model->ccd_type != CCD_HP3670
&& dev->model->ccd_type != CCD_HP2400) */
{
status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error, "gl646_set_fe: writing reg0 failed: %s\n",
sane_strstatus (status));
return status;
}
status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error, "gl646_set_fe: writing reg2 failed: %s\n",
sane_strstatus (status));
return status;
}
}
/* start with reg3 */
status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.reg[3]);
@ -2309,26 +2330,28 @@ gl646_set_fe (Genesys_Device * dev, uint8_t set)
}
}
break;
/* STEF just can't have it to work, seems polarity is inversed
case CCD_HP2300:
status = sanei_genesys_fe_write_data (dev, 0x28, dev->frontend.gain[1]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error, "gl646_set_fe: writing gain[1] failed: %s\n",
sane_strstatus (status));
return status;
}
/* just can't have it to work ....
case CCD_HP2300:
case CCD_HP2400:
case CCD_HP3670:
status =
sanei_genesys_fe_write_data (dev, 0x23, dev->frontend.offset[1]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error,
"gl646_set_fe: writing offset[1] failed: %s\n",
sane_strstatus (status));
return status;
}
break; */
status =
sanei_genesys_fe_write_data (dev, 0x23, dev->frontend.offset[1]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error,
"gl646_set_fe: writing offset[1] failed: %s\n",
sane_strstatus (status));
return status;
}
status = sanei_genesys_fe_write_data (dev, 0x28, dev->frontend.gain[1]);
if (status != SANE_STATUS_GOOD)
{
DBG (DBG_error, "gl646_set_fe: writing gain[1] failed: %s\n",
sane_strstatus (status));
return status;
}
break; */
}
/* end with reg1 */
@ -2754,7 +2777,7 @@ static SANE_Status
gl646_eject_document (Genesys_Device * dev)
{
SANE_Status status = SANE_STATUS_GOOD;
Genesys_Register_Set regs[7];
Genesys_Register_Set regs[11];
unsigned int used, vfinal, count;
uint16_t slope_table[255];
uint8_t val;
@ -3346,7 +3369,7 @@ gl646_init_regs_for_shading (Genesys_Device * dev)
/* when shading all line, we must adapt to half_ccd case */
if ((dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)
&& (dev->settings.xres <= dev->sensor.optical_res / 2))
&& (dev->settings.xres < dev->sensor.optical_res / 2))
{
/* we are going to use half the pixel number */
half_ccd = 2;
@ -3359,7 +3382,7 @@ gl646_init_regs_for_shading (Genesys_Device * dev)
settings.yres = dev->sensor.optical_res / half_ccd;
settings.tl_x = 0;
settings.tl_y = 0;
settings.pixels = dev->sensor.sensor_pixels / half_ccd;
settings.pixels = dev->sensor.sensor_pixels/half_ccd;
settings.lines = dev->model->shading_lines;
settings.depth = 16;
settings.color_filter = dev->settings.color_filter;
@ -3371,11 +3394,15 @@ gl646_init_regs_for_shading (Genesys_Device * dev)
/* we don't want top offset, but we need right margin to be the same
* than the one for the final scan */
status = setup_for_scan (dev, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE);
/* used when sending shading calibration data */
dev->calib_pixels = settings.pixels;
/* no shading */
dev->reg[reg_0x01].value &= ~REG01_DVDSET;
dev->reg[reg_0x02].value |= REG02_ACDCDIS; /* ease backtracking */
dev->reg[reg_0x02].value &= ~(REG02_FASTFED | REG02_AGOHOME);
dev->reg[reg_0x05].value &= ~REG05_GMMENB;
gl646_set_motor_power (dev->reg, SANE_FALSE);
/* TODO another flag to setup regs ? */
@ -3760,7 +3787,14 @@ gl646_offset_calibration (Genesys_Device * dev)
/* setup for a RGB scan, one full sensor's width line */
/* resolution is the one from the final scan */
resolution = get_closest_resolution (dev->model->ccd_type, 150, SANE_TRUE);
if (dev->settings.xres > dev->sensor.optical_res)
{
resolution = get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, SANE_TRUE);
}
else
{
resolution = get_closest_resolution (dev->model->ccd_type, dev->settings.xres, SANE_TRUE);
}
channels = 3;
black_pixels =
(dev->sensor.black_pixels * resolution) / dev->sensor.optical_res;
@ -3788,7 +3822,10 @@ gl646_offset_calibration (Genesys_Device * dev)
dev->frontend.gain[2] = 0;
/* scan with no move */
bottom = 90;
if (dev->model->ccd_type == CIS_XP200)
bottom = 4;
else
bottom = 90;
dev->frontend.offset[0] = bottom;
dev->frontend.offset[1] = bottom;
dev->frontend.offset[2] = bottom;
@ -3801,7 +3838,8 @@ gl646_offset_calibration (Genesys_Device * dev)
}
if (DBG_LEVEL >= DBG_data)
{
sanei_genesys_write_pnm_file ("offset000.pnm", first_line, 8, channels,
sprintf (title, "offset%03d.pnm", bottom);
sanei_genesys_write_pnm_file (title, first_line, 8, channels,
settings.pixels, settings.lines);
}
bottomavg =
@ -3810,7 +3848,10 @@ gl646_offset_calibration (Genesys_Device * dev)
free (first_line);
/* now top value */
top = 231;
if (dev->model->ccd_type == CIS_XP200)
top=0x80;
else
top = 231;
dev->frontend.offset[0] = top;
dev->frontend.offset[1] = top;
dev->frontend.offset[2] = top;
@ -3922,7 +3963,17 @@ gl646_coarse_gain_calibration (Genesys_Device * dev, int dpi)
/* setup for a RGB scan, one full sensor's width line */
/* resolution is the one from the final scan */
channels = 3;
resolution = get_closest_resolution (dev->model->ccd_type, 150, SANE_TRUE);
/* XXX STEF XXX resolution = get_closest_resolution (dev->model->ccd_type, 150, SANE_TRUE); */
/* we are searching a sensor resolution */
if (dev->settings.xres > dev->sensor.optical_res)
{
resolution = get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, SANE_TRUE);
}
else
{
resolution = get_closest_resolution (dev->model->ccd_type, dev->settings.xres, SANE_TRUE);
}
settings.scan_method = SCAN_METHOD_FLATBED;
settings.scan_mode = SCAN_MODE_COLOR;
@ -4061,7 +4112,6 @@ gl646_init_regs_for_warmup (Genesys_Device * dev,
DBG (DBG_proc, "gl646_init_regs_for_warmup: start\n");
/* we scan at sensor maximum resolution */
resolution = get_closest_resolution (dev->model->ccd_type, 300, SANE_FALSE);
/* set up for a half width 2 lines color scan without moving */
@ -4285,9 +4335,8 @@ gl646_init (Genesys_Device * dev)
"gl646_init: could not allocate memory for gamma table\n");
return SANE_STATUS_NO_MEM;
}
sanei_genesys_create_gamma_table (dev->sensor.
green_gamma_table, size,
size - 1, size - 1,
sanei_genesys_create_gamma_table (dev->sensor.green_gamma_table,
size, size - 1, size - 1,
dev->sensor.green_gamma);
}
if (dev->sensor.blue_gamma_table == NULL)
@ -4299,9 +4348,8 @@ gl646_init (Genesys_Device * dev)
"gl646_init: could not allocate memory for gamma table\n");
return SANE_STATUS_NO_MEM;
}
sanei_genesys_create_gamma_table (dev->sensor.
blue_gamma_table, size,
size - 1, size - 1,
sanei_genesys_create_gamma_table (dev->sensor.blue_gamma_table,
size, size - 1, size - 1,
dev->sensor.blue_gamma);
}
@ -4484,8 +4532,9 @@ simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move,
unsigned char **data)
{
SANE_Status status;
unsigned int size, lines;
unsigned int size, lines, x, y, bpp, pixels;
SANE_Bool empty;
unsigned char *buffer;
DBG (DBG_proc, "simple_scan: starting\n");
status = setup_for_scan (dev, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE);
@ -4497,10 +4546,20 @@ simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move,
}
/* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */
lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) + 1;
if (dev->model->is_cis == SANE_TRUE)
{
lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) / 3;
}
else
{
lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) + 1;
}
size = lines * settings.pixels;
if (settings.depth == 16)
size *= 2;
bpp = 2;
else
bpp = 1;
size *= bpp;
if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */
size *= 3;
*data = malloc (size);
@ -4525,18 +4584,15 @@ simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move,
/* no shading correction and not wathc dog for simple scan */
dev->reg[reg_0x01].value &= ~(REG01_DVDSET | REG01_DOGENB);
/* clear motor power flag if no move */
if (move == SANE_FALSE)
{
dev->reg[reg_0x02].value &= ~REG02_MTRPWR;
}
/* one table movement for simple scan */
dev->reg[reg_0x02].value &= ~REG02_FASTFED;
/* no automatic go home if no movement */
if (move == SANE_FALSE)
{
/* clear motor power flag if no move */
dev->reg[reg_0x02].value &= ~REG02_MTRPWR;
/* no automatic go home if no movement */
dev->reg[reg_0x02].value &= ~REG02_AGOHOME;
}
@ -4579,6 +4635,61 @@ simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move,
return status;
}
/* in case of CIS scanner, we must reorder data */
if (dev->model->is_cis == SANE_TRUE
&& settings.scan_mode == SCAN_MODE_COLOR)
{
/* alloc one line sized working buffer */
size = size / settings.lines;
buffer = (unsigned char *) malloc (size);
if (buffer == NULL)
{
DBG (DBG_error,
"simple_scan: failed to allocate %d bytes of memory\n", size);
return SANE_STATUS_NO_MEM;
}
/* reorder one line of data and put it back to buffer */
if (bpp == 1)
{
for (y = 0; y < settings.lines; y++)
{
/* reorder line */
for (x = 0; x < settings.pixels; x++)
{
buffer[x * 3] = (*data)[y * size + x];
buffer[x * 3 + 1] = (*data)[y * size + settings.pixels + x];
buffer[x * 3 + 2] =
(*data)[y * size + 2 * settings.pixels + x];
}
/* copy line back */
memcpy ((*data) + size * y, buffer, size);
}
}
else
{
for (y = 0; y < settings.lines; y++)
{
/* reorder line */
for (x = 0; x < settings.pixels; x++)
{
buffer[x * 6] = (*data)[y * size + x];
buffer[x * 6 + 1] = (*data)[y * size + x + 1];
buffer[x * 6 + 2] = (*data)[y * size + settings.pixels + x];
buffer[x * 6 + 3] =
(*data)[y * size + settings.pixels + x + 1];
buffer[x * 6 + 4] =
(*data)[y * size + 2 * settings.pixels + x];
buffer[x * 6 + 5] =
(*data)[y * size + 2 * settings.pixels + x + 1];
}
/* copy line back */
memcpy ((*data) + size * y, buffer, size);
}
}
free (buffer);
}
/* end scan , waiting the motor to stop if needed (if moving), but without ejecting doc */
status = end_scan (dev, dev->reg, SANE_TRUE, SANE_FALSE);
if (status != SANE_STATUS_GOOD)
@ -4757,11 +4868,11 @@ write_control (Genesys_Device * dev, int resolution)
break;
case MOTOR_5345:
case MOTOR_HP3670:
default:
control[0] = dev->control[2];
control[1] = dev->control[3];
control[2] = dev->control[4];
control[3] = dev->control[5];
default:
break;
}