kopia lustrzana https://gitlab.com/sane-project/backends
Add calibration cache
The calibration data is stored in the directory $HOME/.sanemerge-requests/1/head
rodzic
93b880cbd1
commit
ce2fdfbfbe
|
@ -1,3 +1,7 @@
|
|||
2009-03-25 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
|
||||
* backend/genesys.c, backend/genesys_gl646.c,
|
||||
backend/genesys_gl841.c, backend/genesys_low.h: Add calibration cache
|
||||
|
||||
2009-03-24 m. allan noah <kitno455 a t gmail d o t com>
|
||||
* backend/canon_dr.[ch], backend/canon_dr-cmd.h: backend v21
|
||||
- correct rgb padding macro
|
||||
|
|
|
@ -2247,7 +2247,9 @@ genesys_dark_shading_calibration (Genesys_Device * dev)
|
|||
|
||||
FREE_IFNOT_NULL (dev->dark_average_data);
|
||||
|
||||
dev->dark_average_data = malloc (channels * 2 * pixels_per_line);
|
||||
dev->average_size = channels * 2 * pixels_per_line;
|
||||
|
||||
dev->dark_average_data = malloc (dev->average_size);
|
||||
if (!dev->dark_average_data)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
|
@ -2378,7 +2380,8 @@ genesys_dummy_dark_shading (Genesys_Device * dev)
|
|||
|
||||
FREE_IFNOT_NULL (dev->dark_average_data);
|
||||
|
||||
dev->dark_average_data = malloc (channels * 2 * pixels_per_line);
|
||||
dev->average_size = channels * 2 * pixels_per_line;
|
||||
dev->dark_average_data = malloc (dev->average_size);
|
||||
if (!dev->dark_average_data)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
|
@ -2605,7 +2608,9 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev)
|
|||
if (dev->white_average_data)
|
||||
free (dev->white_average_data);
|
||||
|
||||
dev->white_average_data = malloc (channels * 2 * pixels_per_line);
|
||||
dev->average_size = channels * 2 * pixels_per_line;
|
||||
|
||||
dev->white_average_data = malloc (dev->average_size);
|
||||
if (!dev->white_average_data)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
|
@ -2783,9 +2788,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
|
|||
DBG (DBG_proc, "genesys_send_shading_coefficient\n");
|
||||
|
||||
|
||||
pixels_per_line =
|
||||
(genesys_pixels_per_line (dev->calib_reg)
|
||||
* genesys_dpiset (dev->calib_reg)) / dev->sensor.optical_res;
|
||||
pixels_per_line = dev->calib_pixels;
|
||||
|
||||
if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */
|
||||
channels = 3;
|
||||
|
@ -3281,6 +3284,158 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
|
|||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status
|
||||
genesys_restore_calibration (Genesys_Device * dev)
|
||||
{
|
||||
SANE_Status status;
|
||||
Genesys_Calibration_Cache *cache;
|
||||
|
||||
DBG (DBG_proc, "genesys_restore_calibration\n");
|
||||
|
||||
if (!dev->model->cmd_set->is_compatible_calibration)
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
|
||||
for(cache = dev->calibration_cache; cache; cache = cache->next)
|
||||
{
|
||||
status = dev->model->cmd_set->is_compatible_calibration(dev, cache,
|
||||
SANE_FALSE);
|
||||
if (status == SANE_STATUS_UNSUPPORTED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_restore_calibration: fail while checking compatibility: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
memcpy(&dev->frontend, &cache->frontend, sizeof(dev->frontend));
|
||||
/* don't restore the gamma fields */
|
||||
memcpy(&dev->sensor, &cache->sensor,
|
||||
offsetof(Genesys_Sensor,red_gamma));
|
||||
|
||||
free(dev->dark_average_data);
|
||||
free(dev->white_average_data);
|
||||
|
||||
dev->average_size = cache->average_size;
|
||||
dev->calib_pixels = cache->calib_pixels;
|
||||
|
||||
dev->dark_average_data = (uint8_t*)malloc(cache->average_size);
|
||||
dev->white_average_data = (uint8_t*)malloc(cache->average_size);
|
||||
|
||||
if (!dev->dark_average_data || !dev->white_average_data)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
|
||||
memcpy(dev->dark_average_data,
|
||||
cache->dark_average_data, dev->average_size);
|
||||
memcpy(dev->white_average_data,
|
||||
cache->white_average_data, dev->average_size);
|
||||
|
||||
status = genesys_send_shading_coefficient (dev);
|
||||
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_send_shading_coefficient: failed to send shading data: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
DBG (DBG_proc, "genesys_restore_calibration: restored\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
DBG (DBG_proc, "genesys_restore_calibration: completed(nothing found)\n");
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static SANE_Status
|
||||
genesys_save_calibration (Genesys_Device * dev)
|
||||
{
|
||||
SANE_Status status;
|
||||
Genesys_Calibration_Cache *cache;
|
||||
uint8_t *tmp;
|
||||
|
||||
DBG (DBG_proc, "genesys_save_calibration\n");
|
||||
|
||||
if (!dev->model->cmd_set->is_compatible_calibration)
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
|
||||
for(cache = dev->calibration_cache; cache; 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)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_save_calibration: fail while checking compatibility: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(cache)
|
||||
{
|
||||
if(dev->average_size > cache->average_size)
|
||||
{
|
||||
cache->average_size = dev->average_size;
|
||||
|
||||
tmp = (uint8_t*)realloc(cache->dark_average_data,
|
||||
cache->average_size);
|
||||
if (!tmp)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
cache->dark_average_data = tmp;
|
||||
|
||||
tmp = (uint8_t*)realloc(cache->white_average_data,
|
||||
cache->average_size);
|
||||
if (!tmp)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
cache->white_average_data = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = malloc(sizeof(*cache));
|
||||
if (!cache)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
|
||||
memset(cache, 0, sizeof(*cache));
|
||||
|
||||
cache->next = dev->calibration_cache;
|
||||
dev->calibration_cache = cache;
|
||||
|
||||
cache->average_size = dev->average_size;
|
||||
|
||||
cache->dark_average_data = (uint8_t*)malloc(cache->average_size);
|
||||
if (!cache->dark_average_data)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
cache->white_average_data = (uint8_t*)malloc(cache->average_size);
|
||||
if (!cache->white_average_data)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
|
||||
memcpy(&cache->used_setup, &dev->current_setup,
|
||||
sizeof(cache->used_setup));
|
||||
}
|
||||
|
||||
memcpy(&cache->frontend, &dev->frontend, sizeof(cache->frontend));
|
||||
memcpy(&cache->sensor, &dev->sensor, sizeof(cache->sensor));
|
||||
|
||||
cache->calib_pixels = dev->calib_pixels;
|
||||
memcpy(cache->dark_average_data, dev->dark_average_data,
|
||||
cache->average_size);
|
||||
memcpy(cache->white_average_data, dev->white_average_data,
|
||||
cache->average_size);
|
||||
|
||||
DBG (DBG_proc, "genesys_save_calibration: completed\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status
|
||||
genesys_flatbed_calibration (Genesys_Device * dev)
|
||||
{
|
||||
|
@ -3445,6 +3600,10 @@ genesys_flatbed_calibration (Genesys_Device * dev)
|
|||
return status;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
status = genesys_dark_white_shading_calibration (dev);
|
||||
|
@ -3769,44 +3928,57 @@ genesys_start_scan (Genesys_Device * dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* calibration : sheetfed scanners can't calibrate before each scan */
|
||||
/* so we use a NO_CALIBRATION flags for those scanners */
|
||||
if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)
|
||||
status = genesys_restore_calibration (dev);
|
||||
if(status == SANE_STATUS_UNSUPPORTED)
|
||||
{
|
||||
/* TODO send predefined calibration values from default
|
||||
* values or built from a calibration scan */
|
||||
/* send custom or generic gamma tables depending on flag */
|
||||
if (dev->model->flags & GENESYS_FLAG_CUSTOM_GAMMA)
|
||||
/* calibration : sheetfed scanners can't calibrate before each scan */
|
||||
/* so we use a NO_CALIBRATION flags for those scanners */
|
||||
if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)
|
||||
{
|
||||
/* use custom gamma table */
|
||||
status = dev->model->cmd_set->send_gamma_table (dev, 0);
|
||||
/* TODO send predefined calibration values from default
|
||||
* values or built from a calibration scan */
|
||||
/* send custom or generic gamma tables depending on flag */
|
||||
if (dev->model->flags & GENESYS_FLAG_CUSTOM_GAMMA)
|
||||
{
|
||||
/* use custom gamma table */
|
||||
status = dev->model->cmd_set->send_gamma_table (dev, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send default gamma table if no custom gamma */
|
||||
status = dev->model->cmd_set->send_gamma_table (dev, 1);
|
||||
}
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_start_scan: failed to init gamma table: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* head hasn't moved */
|
||||
dev->scanhead_position_in_steps = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send default gamma table if no custom gamma */
|
||||
status = dev->model->cmd_set->send_gamma_table (dev, 1);
|
||||
}
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_start_scan: failed to init gamma table: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
/* head hasn't moved */
|
||||
dev->scanhead_position_in_steps = 0;
|
||||
status = genesys_flatbed_calibration (dev);
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_start_scan: failed to do flatbed calibration: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
genesys_save_calibration(dev);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(status != SANE_STATUS_GOOD)
|
||||
{
|
||||
status = genesys_flatbed_calibration (dev);
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"genesys_start_scan: failed to do flatbed calibration: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
DBG (DBG_error,
|
||||
"genesys_start_scan: failed to restore calibration: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = dev->model->cmd_set->init_regs_for_scan (dev);
|
||||
|
@ -5312,6 +5484,167 @@ probe_genesys_devices (void)
|
|||
return status;
|
||||
}
|
||||
|
||||
/* this should be changed if one of the substructures of
|
||||
Genesys_Calibration_Cache change, but it must be changed if there are
|
||||
changes that don't change size -- at least for now, as we store most
|
||||
of Genesys_Calibration_Cache as is.
|
||||
*/
|
||||
#define CALIBRATION_VERSION 1
|
||||
|
||||
static void
|
||||
read_calibration(Genesys_Device * dev)
|
||||
{
|
||||
FILE *fp;
|
||||
uint8_t vers = 0;
|
||||
uint32_t size = 0;
|
||||
struct Genesys_Calibration_Cache *cache;
|
||||
|
||||
DBG (DBG_proc, "read_calibration: enter\n");
|
||||
fp = fopen(dev->calib_file,"rb");
|
||||
if (!fp)
|
||||
{
|
||||
DBG ( DBG_info, "Calibration: Cannot open %s\n", dev->calib_file );
|
||||
DBG (DBG_proc, "read_calibration: exit\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* these two checks ensure that most bad things cannot happen */
|
||||
fread(&vers,1,1,fp);
|
||||
if (vers != CALIBRATION_VERSION)
|
||||
{
|
||||
DBG ( DBG_info, "Calibration: Bad version\n" );
|
||||
fclose(fp);
|
||||
DBG (DBG_proc, "read_calibration: exit\n");
|
||||
return;
|
||||
}
|
||||
fread(&size,4,1,fp);
|
||||
if (size != sizeof(struct Genesys_Calibration_Cache))
|
||||
{
|
||||
DBG ( DBG_info, "Calibration: Size of calibration cache struct differs\n" );
|
||||
fclose(fp);
|
||||
DBG (DBG_proc, "read_calibration: exit\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while(!feof(fp))
|
||||
{
|
||||
DBG (DBG_info, "read_calibration: reading one record\n");
|
||||
cache = (struct Genesys_Calibration_Cache *)malloc(sizeof(*cache));
|
||||
|
||||
if (!cache)
|
||||
{
|
||||
DBG (DBG_error, "read_calibration: could not allocate cache struct\n");
|
||||
break;
|
||||
}
|
||||
|
||||
#define BILT1( x ) \
|
||||
do \
|
||||
{ \
|
||||
if ((x) < 1) \
|
||||
{ \
|
||||
free(cache); \
|
||||
DBG (DBG_warn, "read_calibration: partial calibration record\n"); \
|
||||
break; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
if (fread(&cache->used_setup,sizeof(cache->used_setup),1,fp) < 1)
|
||||
{ /* eof is only detected here */
|
||||
free(cache);
|
||||
break;
|
||||
}
|
||||
BILT1(fread(&cache->last_calibration,sizeof(cache->last_calibration),1,fp));
|
||||
BILT1(fread(&cache->frontend,sizeof(cache->frontend),1,fp));
|
||||
/* the gamma (and later) fields are not stored */
|
||||
BILT1(fread(&cache->sensor,offsetof(Genesys_Sensor,red_gamma),1,fp));
|
||||
BILT1(fread(&cache->calib_pixels,sizeof(cache->calib_pixels),1,fp));
|
||||
BILT1(fread(&cache->average_size,sizeof(cache->average_size),1,fp));
|
||||
|
||||
/* Make sure we don't do bad things if someone feeds us a forged/
|
||||
sufficiently corrupted calibration file.
|
||||
gl843 can do up to 0x5800 pixels. add some slack for the
|
||||
dummy/blank pixel mess */
|
||||
if (cache->average_size > 0xb000+0x100)
|
||||
{
|
||||
DBG (DBG_error, "read_calibration: bad size of calibration data\n");
|
||||
free(cache);
|
||||
break;
|
||||
}
|
||||
|
||||
cache->white_average_data = (uint8_t*)malloc(cache->average_size);
|
||||
cache->dark_average_data = (uint8_t*)malloc(cache->average_size);
|
||||
|
||||
if (!cache->white_average_data || !cache->dark_average_data)
|
||||
{
|
||||
FREE_IFNOT_NULL(cache->white_average_data);
|
||||
FREE_IFNOT_NULL(cache->dark_average_data);
|
||||
free(cache);
|
||||
DBG (DBG_error, "read_calibration: could not allocate space for average data\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fread(cache->white_average_data,cache->average_size,1,fp) < 1)
|
||||
{
|
||||
DBG (DBG_warn, "read_calibration: partial calibration record\n");
|
||||
free(cache->white_average_data);
|
||||
free(cache->dark_average_data);
|
||||
free(cache);
|
||||
break;
|
||||
}
|
||||
if (fread(cache->dark_average_data,cache->average_size,1,fp) < 1)
|
||||
{
|
||||
DBG (DBG_warn, "read_calibration: partial calibration record\n");
|
||||
free(cache->white_average_data);
|
||||
free(cache->dark_average_data);
|
||||
free(cache);
|
||||
break;
|
||||
}
|
||||
#undef BILT1
|
||||
DBG (DBG_info, "read_calibration: adding record to list\n");
|
||||
cache->next = dev->calibration_cache;
|
||||
dev->calibration_cache = cache;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
DBG (DBG_proc, "read_calibration: exit\n");
|
||||
}
|
||||
|
||||
static void
|
||||
write_calibration(Genesys_Device * dev)
|
||||
{
|
||||
FILE *fp;
|
||||
uint8_t vers = 0;
|
||||
uint32_t size = 0;
|
||||
struct Genesys_Calibration_Cache *cache;
|
||||
fp = fopen(dev->calib_file,"wb");
|
||||
if (!fp)
|
||||
{
|
||||
DBG ( DBG_info, "Calibration: Cannot open %s\n", dev->calib_file );
|
||||
return;
|
||||
}
|
||||
|
||||
vers = CALIBRATION_VERSION;
|
||||
fwrite(&vers,1,1,fp);
|
||||
size = sizeof(struct Genesys_Calibration_Cache);
|
||||
fwrite(&size,4,1,fp);
|
||||
|
||||
for(cache = dev->calibration_cache; cache; cache = cache->next)
|
||||
{
|
||||
fwrite(&cache->used_setup,sizeof(cache->used_setup),1,fp);
|
||||
fwrite(&cache->last_calibration,sizeof(cache->last_calibration),1,fp);
|
||||
fwrite(&cache->frontend,sizeof(cache->frontend),1,fp);
|
||||
/* the gamma (and later) fields are not stored */
|
||||
fwrite(&cache->sensor,offsetof(Genesys_Sensor,red_gamma),1,fp);
|
||||
fwrite(&cache->calib_pixels,sizeof(cache->calib_pixels),1,fp);
|
||||
fwrite(&cache->average_size,sizeof(cache->average_size),1,fp);
|
||||
fwrite(cache->white_average_data,cache->average_size,1,fp);
|
||||
fwrite(cache->dark_average_data,cache->average_size,1,fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/* -------------------------- SANE API functions ------------------------- */
|
||||
|
||||
SANE_Status
|
||||
|
@ -5424,6 +5757,8 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|||
Genesys_Device *dev;
|
||||
SANE_Status status;
|
||||
Genesys_Scanner *s;
|
||||
char tmp_str[PATH_MAX];
|
||||
char *ptr;
|
||||
|
||||
DBG (DBG_proc, "sane_open: start (devicename = `%s')\n", devicename);
|
||||
|
||||
|
@ -5499,6 +5834,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|||
s->dev->read_active = SANE_FALSE;
|
||||
s->dev->white_average_data = NULL;
|
||||
s->dev->dark_average_data = NULL;
|
||||
s->dev->calibration_cache = NULL;
|
||||
|
||||
/* insert newly opened handle into list of open handles: */
|
||||
s->next = first_handle;
|
||||
|
@ -5518,6 +5854,31 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
|
|||
|
||||
RIE (dev->model->cmd_set->init (dev));
|
||||
|
||||
/* here is the place to fetch a stored calibration cache */
|
||||
|
||||
/* create calibration-filename
|
||||
lifted from plustek-usb.c
|
||||
*/
|
||||
/* we should add a unique identifying feature to the file name
|
||||
to support multiple scanners of the same model, but to my
|
||||
knowledge, there is no such thing in these scanners.
|
||||
(At least the usb serial is always "0".)
|
||||
*/
|
||||
|
||||
ptr = getenv ("HOME");
|
||||
if( NULL == ptr ) {
|
||||
sprintf( tmp_str, "/tmp/%s.cal", s->dev->model->name );
|
||||
} else {
|
||||
sprintf( tmp_str, "%s/.sane/%s.cal", ptr, s->dev->model->name );
|
||||
}
|
||||
s->dev->calib_file = strdup( tmp_str );
|
||||
DBG( DBG_info, "Calibration filename set to:\n" );
|
||||
DBG( DBG_info, ">%s<\n", s->dev->calib_file );
|
||||
|
||||
/* now open file, fetch calibration records */
|
||||
|
||||
read_calibration(s->dev);
|
||||
|
||||
DBG (DBG_proc, "sane_open: exit\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
@ -5526,6 +5887,7 @@ void
|
|||
sane_close (SANE_Handle handle)
|
||||
{
|
||||
Genesys_Scanner *prev, *s;
|
||||
Genesys_Calibration_Cache *cache, *next_cache;
|
||||
|
||||
DBG (DBG_proc, "sane_close: start\n");
|
||||
|
||||
|
@ -5543,6 +5905,17 @@ sane_close (SANE_Handle handle)
|
|||
return; /* oops, not a handle we know about */
|
||||
}
|
||||
|
||||
/* here is the place to store calibration cache */
|
||||
write_calibration(s->dev);
|
||||
|
||||
for(cache = s->dev->calibration_cache; cache; cache = next_cache)
|
||||
{
|
||||
next_cache = cache->next;
|
||||
free(cache->dark_average_data);
|
||||
free(cache->white_average_data);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
sanei_genesys_buffer_free (&(s->dev->read_buffer));
|
||||
sanei_genesys_buffer_free (&(s->dev->lines_buffer));
|
||||
sanei_genesys_buffer_free (&(s->dev->shrink_buffer));
|
||||
|
|
|
@ -4821,10 +4821,14 @@ static Genesys_Command_Set gl646_cmd_set = {
|
|||
gl646_bulk_write_register,
|
||||
gl646_bulk_write_data,
|
||||
gl646_bulk_read_data,
|
||||
|
||||
gl646_update_hardware_sensors,
|
||||
|
||||
gl646_load_document,
|
||||
gl646_detect_document_end,
|
||||
gl646_eject_document,
|
||||
|
||||
NULL,/*is_compatible_calibration*/
|
||||
};
|
||||
|
||||
SANE_Status
|
||||
|
|
|
@ -3077,6 +3077,273 @@ dummy \ scanned lines
|
|||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status
|
||||
gl841_calculate_current_setup (Genesys_Device * dev)
|
||||
{
|
||||
int channels;
|
||||
int depth;
|
||||
int start;
|
||||
|
||||
float xres;/*dpi*/
|
||||
float yres;/*dpi*/
|
||||
float startx;/*optical_res, from dummy_pixel+1*/
|
||||
float pixels;
|
||||
float lines;
|
||||
int color_filter;
|
||||
|
||||
int used_res;
|
||||
int used_pixels;
|
||||
unsigned int lincnt;
|
||||
int exposure_time, exposure_time2, led_exposure;
|
||||
int i;
|
||||
int stagger;
|
||||
|
||||
int slope_dpi = 0;
|
||||
int dummy = 0;
|
||||
int scan_step_type = 1;
|
||||
int scan_power_mode = 0;
|
||||
int max_shift;
|
||||
|
||||
SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */
|
||||
int optical_res;
|
||||
|
||||
DBG (DBG_info,
|
||||
"gl841_calculate_current_setup settings:\n"
|
||||
"Resolution: %uDPI\n"
|
||||
"Lines : %u\n"
|
||||
"PPL : %u\n"
|
||||
"Startpos : %.3f/%.3f\n"
|
||||
"Scan mode : %d\n\n",
|
||||
dev->settings.yres, dev->settings.lines, dev->settings.pixels,
|
||||
dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode);
|
||||
|
||||
/* channels */
|
||||
if (dev->settings.scan_mode == 4) /* single pass color */
|
||||
channels = 3;
|
||||
else
|
||||
channels = 1;
|
||||
|
||||
/* depth */
|
||||
depth = dev->settings.depth;
|
||||
if (dev->settings.scan_mode == 0)
|
||||
depth = 1;
|
||||
|
||||
/* start */
|
||||
start = SANE_UNFIX (dev->model->x_offset);
|
||||
|
||||
start += dev->settings.tl_x;
|
||||
|
||||
start = (start * dev->sensor.optical_res) / MM_PER_INCH;
|
||||
|
||||
|
||||
xres = dev->settings.xres;/*dpi*/
|
||||
yres = dev->settings.yres;/*dpi*/
|
||||
startx = start;/*optical_res, from dummy_pixel+1*/
|
||||
pixels = dev->settings.pixels;
|
||||
lines = dev->settings.lines;
|
||||
color_filter = dev->settings.color_filter;
|
||||
|
||||
|
||||
DBG (DBG_info,
|
||||
"gl841_calculate_current_setup settings:\n"
|
||||
"Resolution : %gDPI/%gDPI\n"
|
||||
"Lines : %g\n"
|
||||
"PPL : %g\n"
|
||||
"Startpos : %g\n"
|
||||
"Depth/Channels: %u/%u\n\n",
|
||||
xres, yres, lines, pixels,
|
||||
startx,
|
||||
depth, channels);
|
||||
|
||||
/* half_ccd */
|
||||
/* we have 2 domains for ccd: xres below or above half ccd max dpi */
|
||||
if (dev->sensor.optical_res < 2 * xres) {
|
||||
half_ccd = SANE_FALSE;
|
||||
} else {
|
||||
half_ccd = SANE_TRUE;
|
||||
}
|
||||
|
||||
/* optical_res */
|
||||
|
||||
optical_res = dev->sensor.optical_res;
|
||||
if (half_ccd)
|
||||
optical_res /= 2;
|
||||
|
||||
/* stagger */
|
||||
|
||||
if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE))
|
||||
stagger = (4 * yres) / dev->motor.base_ydpi;
|
||||
else
|
||||
stagger = 0;
|
||||
DBG (DBG_info, "gl841_calculate_current_setup: stagger=%d lines\n",
|
||||
stagger);
|
||||
|
||||
/* used_res */
|
||||
i = optical_res / xres;
|
||||
|
||||
/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */
|
||||
|
||||
if (i < 2) /* optical_res >= xres > optical_res/2 */
|
||||
used_res = optical_res;
|
||||
else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */
|
||||
used_res = optical_res/2;
|
||||
else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */
|
||||
used_res = optical_res/3;
|
||||
else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */
|
||||
used_res = optical_res/4;
|
||||
else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */
|
||||
used_res = optical_res/5;
|
||||
else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */
|
||||
used_res = optical_res/6;
|
||||
else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */
|
||||
used_res = optical_res/8;
|
||||
else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */
|
||||
used_res = optical_res/10;
|
||||
else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */
|
||||
used_res = optical_res/12;
|
||||
else
|
||||
used_res = optical_res/15;
|
||||
|
||||
/* compute scan parameters values */
|
||||
/* pixels are allways given at half or full CCD optical resolution */
|
||||
/* use detected left margin and fixed value */
|
||||
/* start */
|
||||
/* add x coordinates */
|
||||
start =
|
||||
((dev->sensor.CCD_start_xoffset + startx) * used_res) /
|
||||
dev->sensor.optical_res;
|
||||
|
||||
/* needs to be aligned for used_res */
|
||||
start = (start * optical_res) / used_res;
|
||||
|
||||
start += dev->sensor.dummy_pixel + 1;
|
||||
|
||||
if (stagger > 0)
|
||||
start |= 1;
|
||||
|
||||
/* compute correct pixels number */
|
||||
/* pixels */
|
||||
used_pixels =
|
||||
(pixels * optical_res) / xres;
|
||||
|
||||
/* round up pixels number if needed */
|
||||
if (used_pixels * xres < pixels * optical_res)
|
||||
used_pixels++;
|
||||
|
||||
/* dummy */
|
||||
/* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1
|
||||
dummy line. Maybe the dummy line adds correctness since the motor runs
|
||||
slower (higher dpi)
|
||||
*/
|
||||
/* for cis this creates better aligned color lines:
|
||||
dummy \ scanned lines
|
||||
0: R G B R ...
|
||||
1: R G B - R ...
|
||||
2: R G B - - R ...
|
||||
3: R G B - - - R ...
|
||||
4: R G B - - - - R ...
|
||||
5: R G B - - - - - R ...
|
||||
6: R G B - - - - - - R ...
|
||||
7: R G B - - - - - - - R ...
|
||||
8: R G B - - - - - - - - R ...
|
||||
9: R G B - - - - - - - - - R ...
|
||||
10: R G B - - - - - - - - - - R ...
|
||||
11: R G B - - - - - - - - - - - R ...
|
||||
12: R G B - - - - - - - - - - - - R ...
|
||||
13: R G B - - - - - - - - - - - - - R ...
|
||||
14: R G B - - - - - - - - - - - - - - R ...
|
||||
15: R G B - - - - - - - - - - - - - - - R ...
|
||||
-- pierre
|
||||
*/
|
||||
dummy = 0;
|
||||
|
||||
/* slope_dpi */
|
||||
/* cis color scan is effectively a gray scan with 3 gray lines per color
|
||||
line and a FILTER of 0 */
|
||||
if (dev->model->is_cis)
|
||||
slope_dpi = yres*channels;
|
||||
else
|
||||
slope_dpi = yres;
|
||||
|
||||
slope_dpi = slope_dpi * (1 + dummy);
|
||||
|
||||
/* scan_step_type */
|
||||
/* Try to do at least 4 steps per line. if that is impossible we will have to
|
||||
live with that
|
||||
*/
|
||||
if (yres*4 < dev->motor.base_ydpi
|
||||
|| dev->motor.max_step_type <= 0)
|
||||
scan_step_type = 0;
|
||||
else if (yres*4 < dev->motor.base_ydpi*2
|
||||
|| dev->motor.max_step_type <= 1)
|
||||
scan_step_type = 1;
|
||||
else
|
||||
scan_step_type = 2;
|
||||
|
||||
led_exposure = gl841_get_led_exposure(dev);
|
||||
|
||||
/* exposure_time */
|
||||
exposure_time = sanei_genesys_exposure_time2(
|
||||
dev,
|
||||
slope_dpi,
|
||||
scan_step_type,
|
||||
start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
|
||||
led_exposure,
|
||||
scan_power_mode);
|
||||
|
||||
while(scan_power_mode + 1 < dev->motor.power_mode_count) {
|
||||
exposure_time2 = sanei_genesys_exposure_time2(
|
||||
dev,
|
||||
slope_dpi,
|
||||
scan_step_type,
|
||||
start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/
|
||||
led_exposure,
|
||||
scan_power_mode + 1);
|
||||
if (exposure_time < exposure_time2)
|
||||
break;
|
||||
exposure_time = exposure_time2;
|
||||
scan_power_mode++;
|
||||
}
|
||||
|
||||
DBG (DBG_info, "gl841_calculate_current_setup : exposure_time=%d pixels\n",
|
||||
exposure_time);
|
||||
|
||||
/* max_shift */
|
||||
/* scanned area must be enlarged by max color shift needed */
|
||||
/* all values are assumed >= 0 */
|
||||
if (channels > 1)
|
||||
{
|
||||
max_shift = dev->model->ld_shift_r;
|
||||
if (dev->model->ld_shift_b > max_shift)
|
||||
max_shift = dev->model->ld_shift_b;
|
||||
if (dev->model->ld_shift_g > max_shift)
|
||||
max_shift = dev->model->ld_shift_g;
|
||||
max_shift =
|
||||
(max_shift * yres) / dev->motor.base_ydpi;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_shift = 0;
|
||||
}
|
||||
|
||||
/* lincnt */
|
||||
lincnt = lines + max_shift + stagger;
|
||||
|
||||
dev->current_setup.pixels = (used_pixels * used_res)/optical_res;
|
||||
dev->current_setup.lines = lincnt;
|
||||
dev->current_setup.depth = depth;
|
||||
dev->current_setup.channels = channels;
|
||||
dev->current_setup.exposure_time = exposure_time;
|
||||
dev->current_setup.xres = used_res;
|
||||
dev->current_setup.yres = yres;
|
||||
dev->current_setup.half_ccd = half_ccd;
|
||||
dev->current_setup.stagger = stagger;
|
||||
dev->current_setup.max_shift = max_shift + stagger;
|
||||
|
||||
DBG (DBG_proc, "gl841_calculate_current_setup: completed\n");
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static void
|
||||
gl841_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set)
|
||||
{
|
||||
|
@ -5290,7 +5557,36 @@ sanei_gl841_repark_head (Genesys_Device * dev)
|
|||
return status;
|
||||
}
|
||||
|
||||
static SANE_Status
|
||||
gl841_is_compatible_calibration (Genesys_Device * dev,
|
||||
Genesys_Calibration_Cache *cache,
|
||||
int for_overwrite)
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
DBG (DBG_proc, "gl841_is_compatible_calibration\n");
|
||||
|
||||
status = gl841_calculate_current_setup (dev);
|
||||
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_error,
|
||||
"gl841_is_compatible_calibration: failed to calculate current setup: %s\n",
|
||||
sane_strstatus (status));
|
||||
return status;
|
||||
}
|
||||
|
||||
DBG (DBG_proc, "gl841_is_compatible_calibration: checking\n");
|
||||
|
||||
if (dev->current_setup.channels != cache->used_setup.channels)
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
if (dev->current_setup.half_ccd != cache->used_setup.half_ccd)
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
|
||||
DBG (DBG_proc, "gl841_is_compatible_calibration: completed\n");
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize ASIC : registers, motor tables, and gamma tables
|
||||
|
@ -5560,6 +5856,7 @@ static Genesys_Command_Set gl841_cmd_set = {
|
|||
gl841_detect_document_end,
|
||||
gl841_eject_document,
|
||||
|
||||
gl841_is_compatible_calibration,
|
||||
};
|
||||
|
||||
SANE_Status
|
||||
|
|
|
@ -294,6 +294,7 @@ Genesys_Color_Order;
|
|||
/* Forward typedefs */
|
||||
typedef struct Genesys_Device Genesys_Device;
|
||||
struct Genesys_Scanner;
|
||||
typedef struct Genesys_Calibration_Cache Genesys_Calibration_Cache;
|
||||
|
||||
/**
|
||||
* Scanner command set description.
|
||||
|
@ -392,6 +393,11 @@ typedef struct Genesys_Command_Set
|
|||
* eject document from scanner
|
||||
*/
|
||||
SANE_Status (*eject_document) (Genesys_Device * dev);
|
||||
|
||||
SANE_Status (*is_compatible_calibration) (
|
||||
Genesys_Device * dev,
|
||||
Genesys_Calibration_Cache *cache,
|
||||
SANE_Bool for_overwrite);
|
||||
} Genesys_Command_Set;
|
||||
|
||||
typedef struct Genesys_Model
|
||||
|
@ -508,10 +514,27 @@ typedef struct Genesys_Buffer
|
|||
size_t avail; /* data bytes currently in buffer */
|
||||
} Genesys_Buffer;
|
||||
|
||||
struct Genesys_Calibration_Cache
|
||||
{
|
||||
Genesys_Current_Setup used_setup;/* used to check if entry is compatible */
|
||||
time_t last_calibration;
|
||||
|
||||
Genesys_Frontend frontend;
|
||||
Genesys_Sensor sensor;
|
||||
|
||||
size_t calib_pixels;
|
||||
size_t average_size;
|
||||
uint8_t *white_average_data;
|
||||
uint8_t *dark_average_data;
|
||||
|
||||
struct Genesys_Calibration_Cache *next;
|
||||
};
|
||||
|
||||
struct Genesys_Device
|
||||
{
|
||||
SANE_Int dn;
|
||||
SANE_String file_name;
|
||||
SANE_String calib_file;
|
||||
Genesys_Model *model;
|
||||
|
||||
Genesys_Register_Set reg[GENESYS_MAX_REGS];
|
||||
|
@ -526,6 +549,8 @@ struct Genesys_Device
|
|||
uint8_t control[6];
|
||||
time_t init_date;
|
||||
|
||||
size_t average_size;
|
||||
size_t calib_pixels;
|
||||
uint8_t *white_average_data;
|
||||
uint8_t *dark_average_data;
|
||||
uint16_t dark[3];
|
||||
|
@ -551,6 +576,8 @@ struct Genesys_Device
|
|||
|
||||
Genesys_Current_Setup current_setup; /* contains the real used values */
|
||||
|
||||
Genesys_Calibration_Cache *calibration_cache;
|
||||
|
||||
struct Genesys_Device *next;
|
||||
};
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue