canon_dr backend version 33, brightness/contrast and despeckle support

- add software brightness/contrast for dumb scanners
- add blocking mode to allow full-page manipulation options to run
- add swdespeck option and support code
- add swdeskew and swcrop options (disabled)
merge-requests/1/head
m. allan noah 2009-07-23 10:54:18 -04:00
rodzic 4780e307cf
commit 0ea4d7bc4b
4 zmienionych plików z 430 dodań i 10 usunięć

Wyświetl plik

@ -345,7 +345,7 @@ libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c
libsane_canon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(USB_LIBS)
libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS)
EXTRA_DIST += canon_dr.conf.in
libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h

Wyświetl plik

@ -1812,7 +1812,7 @@ libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c
libsane_canon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(USB_LIBS)
libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS)
libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h
libcanon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp
nodist_libsane_canon_pp_la_SOURCES = canon_pp-s.c

Wyświetl plik

@ -60,6 +60,7 @@
Section 5 - calibration functions
Section 6 - sane_close functions
Section 7 - misc functions
Section 8 - image processing functions
Changes:
v1 2008-10-29, MAN
@ -235,6 +236,11 @@
- correct some debug message
- better handling of EOF
- add intermediate param struct to existing user and scan versions
v33 2009-07-23, MAN
- add software brightness/contrast for dumb scanners
- add blocking mode to allow full-page manipulation options to run
- add swdespeck option and support code
- add swdeskew and swcrop options (disabled)
SANE FLOW DIAGRAM
@ -295,7 +301,7 @@
#include "canon_dr.h"
#define DEBUG 1
#define BUILD 30
#define BUILD 33
/* values for SANE_DEBUG_CANON_DR env var:
- errors 5
@ -1169,6 +1175,7 @@ init_model (struct scanner *s)
s->duplex_interlace = DUPLEX_INTERLACE_2510;
s->need_ccal = 1;
s->need_fcal = 1;
s->sw_lut = 1;
/*s->invert_tly = 1;*/
/*only in Y direction, so we trash them in X*/
@ -1193,6 +1200,7 @@ init_model (struct scanner *s)
s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB;
s->duplex_interlace = DUPLEX_INTERLACE_FBFB;
s->need_fcal_buffer = 1;
s->sw_lut = 1;
/*lies*/
s->can_halftone=0;
@ -1881,6 +1889,51 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->cap = SANE_CAP_INACTIVE;
}
/*deskew by software*/
if(option==OPT_SWDESKEW){
opt->name = "swdeskew";
opt->title = "Software deskew";
opt->desc = "Request driver to rotate skewed pages digitally";
opt->type = SANE_TYPE_BOOL;
if (1)
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
else
opt->cap = SANE_CAP_INACTIVE;
}
/*software despeckle radius*/
if(option==OPT_SWDESPECK){
opt->name = "swdespeck";
opt->title = "Software despeckle diameter";
opt->desc = "Maximum diameter of lone dots to remove from scan";
opt->type = SANE_TYPE_INT;
opt->unit = SANE_UNIT_NONE;
opt->constraint_type = SANE_CONSTRAINT_RANGE;
opt->constraint.range = &s->swdespeck_range;
s->swdespeck_range.quant=1;
if(1){
s->swdespeck_range.min=0;
s->swdespeck_range.max=9;
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
}
else
opt->cap = SANE_CAP_INACTIVE;
}
/*crop by software*/
if(option==OPT_SWCROP){
opt->name = "swcrop";
opt->title = "Software crop";
opt->desc = "Request driver to remove border from pages digitally";
opt->type = SANE_TYPE_BOOL;
if (1)
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
else
opt->cap = SANE_CAP_INACTIVE;
}
/*staple detection*/
if(option==OPT_STAPLEDETECT){
opt->name = "stapledetect";
@ -2216,6 +2269,18 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
*val_p = s->rollerdeskew;
return SANE_STATUS_GOOD;
case OPT_SWDESKEW:
*val_p = s->swdeskew;
return SANE_STATUS_GOOD;
case OPT_SWDESPECK:
*val_p = s->swdespeck;
return SANE_STATUS_GOOD;
case OPT_SWCROP:
*val_p = s->swcrop;
return SANE_STATUS_GOOD;
case OPT_STAPLEDETECT:
*val_p = s->stapledetect;
return SANE_STATUS_GOOD;
@ -2507,6 +2572,18 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
s->rollerdeskew = val_c;
return SANE_STATUS_GOOD;
case OPT_SWDESKEW:
s->swdeskew = val_c;
return SANE_STATUS_GOOD;
case OPT_SWDESPECK:
s->swdespeck = val_c;
return SANE_STATUS_GOOD;
case OPT_SWCROP:
s->swcrop = val_c;
return SANE_STATUS_GOOD;
case OPT_STAPLEDETECT:
s->stapledetect = val_c;
return SANE_STATUS_GOOD;
@ -3118,6 +3195,12 @@ sane_start (SANE_Handle handle)
return SANE_STATUS_INVAL;
}
/* note if user has requested an option that will require us to
* hold the entire image in memory before we send it to them */
s->blocking_mode = 0;
if(s->swdeskew || s->swdespeck || s->swcrop)
s->blocking_mode = 1;
/* batch start? inititalize struct and scanner */
if(!s->started){
@ -3141,6 +3224,13 @@ sane_start (SANE_Handle handle)
goto errors;
}
/* load the brightness/contrast lut with linear slope for calibration */
ret = load_lut (s->lut, 8, 8, 0, 255, 0, 0);
if (ret != SANE_STATUS_GOOD) {
DBG (5, "sane_start: ERROR: cannot load lut\n");
goto errors;
}
/* AFE cal */
if((ret = calibrate_AFE(s))){
DBG (5, "sane_start: ERROR: cannot cal afe\n");
@ -3214,6 +3304,13 @@ sane_start (SANE_Handle handle)
goto errors;
}
/* load the brightness/contrast lut with user choices */
ret = load_lut (s->lut, 8, 8, 0, 255, s->contrast, s->brightness);
if (ret != SANE_STATUS_GOOD) {
DBG (5, "sane_start: ERROR: cannot load lut\n");
goto errors;
}
/* grab next page */
ret = object_position (s, SANE_TRUE);
if (ret != SANE_STATUS_GOOD) {
@ -3304,14 +3401,11 @@ sane_start (SANE_Handle handle)
DBG (15, "started=%d, side=%d, source=%d\n",
s->started, s->side, s->u.source);
#if 0
s->blocking_mode = 1;
/* certain options require the entire image to
* be collected from the scanner before we can
* tell the user the size of the image. the sane
* API has no way to inform the frontend of this,
* so we block. yuck */
* so we block and buffer. yuck */
if(s->blocking_mode){
/* get image */
@ -3326,10 +3420,14 @@ sane_start (SANE_Handle handle)
goto errors;
}
/* finished buffering, adjust image as required */
DBG (5, "sane_start: OK: done buffering\n");
/* finished buffering, adjust image as required */
if(s->swdespeck){
buffer_despeck(s,s->side);
}
}
#endif
ret = check_for_cancel(s);
s->reading = 0;
@ -4256,6 +4354,14 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side)
}
}
/* apply brightness and contrast if hardware cannot do it */
if(s->sw_lut && (s->s.mode == MODE_COLOR || s->s.mode == MODE_GRAYSCALE)){
DBG (15, "copy_simplex: apply brightness/contrast\n");
for(j=0; j<s->s.valid_Bpl; j++){
line[j] = s->lut[line[j]];
}
}
/*copy the line into the buffer*/
ret = copy_line(s,line,side);
if(ret){
@ -6333,3 +6439,298 @@ sane_get_select_fd (SANE_Handle h, SANE_Int *fdp)
DBG (15, "%p %d\n", h, *fdp);
return SANE_STATUS_UNSUPPORTED;
}
/*
* @@ Section 8 - Image processing functions
*/
static SANE_Status
buffer_despeck(struct scanner *s, int side)
{
SANE_Status ret = SANE_STATUS_GOOD;
int i,j,k,l,n;
int w = s->i.Bpl;
int pw = s->i.width;
int h = s->i.height;
int t = w*h;
int d = s->swdespeck;
DBG (10, "buffer_despeck: start\n");
switch (s->i.mode){
case MODE_COLOR:
for(i=w; i<t-w-(w*d); i+=w){
for(j=1; j<pw-1-d; j++){
int thresh = 255*3;
int outer[] = {0,0,0};
int hits = 0;
/*loop over rows and columns in window */
for(k=0; k<d; k++){
for(l=0; l<d; l++){
int tmp = 0;
for(n=0; n<3; n++){
tmp += s->buffers[side][i + j*3 + k*w + l*3 + n];
}
if(tmp < thresh)
thresh = tmp;
}
}
thresh = (thresh + 255*3 + 255*3)/3;
/*loop over rows and columns around window */
for(k=-1; k<d+1; k++){
for(l=-1; l<d+1; l++){
int tmp[3];
/* dont count pixels in the window */
if(k != -1 && k != d && l != -1 && l != d)
continue;
for(n=0; n<3; n++){
tmp[n] = s->buffers[side][i + j*3 + k*w + l*3 + n];
outer[n] += tmp[n];
}
if(tmp[0]+tmp[1]+tmp[2] < thresh){
hits++;
break;
}
}
}
for(n=0; n<3; n++){
outer[n] /= (4*d + 4);
}
/*no hits, overwrite with avg surrounding color*/
if(!hits){
for(k=0; k<d; k++){
for(l=0; l<d; l++){
for(n=0; n<3; n++){
s->buffers[side][i + j*3 + k*w + l*3 + n] = outer[n];
}
}
}
}
}
}
break;
case MODE_GRAYSCALE:
for(i=w; i<t-w-(w*d); i+=w){
for(j=1; j<w-1-d; j++){
int thresh = 255;
int outer = 0;
int hits = 0;
for(k=0; k<d; k++){
for(l=0; l<d; l++){
if(s->buffers[side][i + j + k*w + l] < thresh)
thresh = s->buffers[side][i + j + k*w + l];
}
}
thresh = (thresh + 255 + 255)/3;
/*loop over rows and columns around window */
for(k=-1; k<d+1; k++){
for(l=-1; l<d+1; l++){
int tmp = 0;
/* dont count pixels in the window */
if(k != -1 && k != d && l != -1 && l != d)
continue;
tmp = s->buffers[side][i + j + k*w + l];
if(tmp < thresh){
hits++;
break;
}
outer += tmp;
}
}
outer /= (4*d + 4);
/*no hits, overwrite with avg surrounding color*/
if(!hits){
for(k=0; k<d; k++){
for(l=0; l<d; l++){
s->buffers[side][i + j + k*w + l] = outer;
}
}
}
}
}
break;
case MODE_LINEART:
case MODE_HALFTONE:
for(i=w; i<t-w-(w*d); i+=w){
for(j=1; j<pw-1-d; j++){
int curr = 0;
int hits = 0;
for(k=0; k<d; k++){
for(l=0; l<d; l++){
curr += s->buffers[side][i + k*w + (j+l)/8] >> (7-(j+l)%8) & 1;
}
}
if(!curr)
continue;
/*loop over rows and columns around window */
for(k=-1; k<d+1; k++){
for(l=-1; l<d+1; l++){
/* dont count pixels in the window */
if(k != -1 && k != d && l != -1 && l != d)
continue;
hits += s->buffers[side][i + k*w + (j+l)/8] >> (7-(j+l)%8) & 1;
if(hits)
break;
}
}
/*no hits, overwrite with white*/
if(!hits){
for(k=0; k<d; k++){
for(l=0; l<d; l++){
s->buffers[side][i + k*w + (j+l)/8] &= ~(1 << (7-(j+l)%8));
}
}
}
}
}
break;
default:
break;
}
DBG (10, "buffer_despeck: finish\n");
return ret;
}
static SANE_Status
buffer_deskew(struct scanner *s, int side)
{
SANE_Status ret = SANE_STATUS_GOOD;
DBG (10, "buffer_deskew: start\n");
DBG (10, "buffer_deskew: finish\n");
return ret;
}
static SANE_Status
buffer_crop(struct scanner *s, int side)
{
SANE_Status ret = SANE_STATUS_GOOD;
DBG (10, "buffer_crop: start\n");
DBG (10, "buffer_crop: finish\n");
return ret;
}
/* Function to build a lookup table (LUT), often
used by scanners to implement brightness/contrast/gamma
or by backends to speed binarization/thresholding
offset and slope inputs are -127 to +127
slope rotates line around central input/output val,
0 makes horizontal line
pos zero neg
. x . . x
. x . . x
out . x .xxxxxxxxxxx . x
. x . . x
....x....... ............ .......x....
in in in
offset moves line vertically, and clamps to output range
0 keeps the line crossing the center of the table
pos zero neg
. xxxxxxxx . xx .
. x . x .
out x . x . x
. . x . x
............ xx.......... xxxxxxxx....
in in
out_min/max provide bounds on output values,
useful when building thresholding lut.
0 and 255 are good defaults otherwise.
*/
static SANE_Status
load_lut (unsigned char * lut,
int in_bits, int out_bits,
int out_min, int out_max,
int slope, int offset)
{
SANE_Status ret = SANE_STATUS_GOOD;
int i, j;
double shift, rise;
int max_in_val = (1 << in_bits) - 1;
int max_out_val = (1 << out_bits) - 1;
unsigned char * lut_p = lut;
DBG (10, "load_lut: start %d %d\n", slope, offset);
/* slope is converted to rise per unit run:
* first [-127,127] to [-.999,.999]
* then to [-PI/4,PI/4] then [0,PI/2]
* then take the tangent (T.O.A)
* then multiply by the normal linear slope
* because the table may not be square, i.e. 1024x256*/
rise = tan((double)slope/128 * M_PI_4 + M_PI_4) * max_out_val / max_in_val;
/* line must stay vertically centered, so figure
* out vertical offset at central input value */
shift = (double)max_out_val/2 - (rise*max_in_val/2);
/* convert the user offset setting to scale of output
* first [-127,127] to [-1,1]
* then to [-max_out_val/2,max_out_val/2]*/
shift += (double)offset / 127 * max_out_val / 2;
for(i=0;i<=max_in_val;i++){
j = rise*i + shift;
if(j<out_min){
j=out_min;
}
else if(j>out_max){
j=out_max;
}
*lut_p=j;
lut_p++;
}
hexdump(5, "load_lut: ", lut, max_in_val+1);
DBG (10, "load_lut: finish\n");
return ret;
}

Wyświetl plik

@ -40,6 +40,9 @@ enum scanner_Option
OPT_DF_THICKNESS,
OPT_DF_LENGTH,
OPT_ROLLERDESKEW,
OPT_SWDESKEW,
OPT_SWDESPECK,
OPT_SWCROP,
OPT_STAPLEDETECT,
OPT_DROPOUT_COLOR_F,
OPT_DROPOUT_COLOR_B,
@ -185,6 +188,8 @@ struct scanner
int duplex_interlace; /* different models interlace sides differently */
int jpeg_interlace; /* different models interlace jpeg sides differently */
int sw_lut; /* no hardware brightness/contrast support */
int reverse_by_mode[6]; /* mode specific */
/* --------------------------------------------------------------------- */
@ -227,6 +232,7 @@ struct scanner
/*advanced group*/
SANE_String_Const compress_list[3];
SANE_Range compress_arg_range;
SANE_Range swdespeck_range;
SANE_String_Const do_color_list[8];
/*sensor group*/
@ -235,7 +241,7 @@ struct scanner
/* --------------------------------------------------------------------- */
/* changeable vars to hold user input. modified by SANE_Options above */
/* the user image params (for final image output) */
/* the user's requested image params */
/* exposed in standard and geometry option groups */
struct img_params u;
@ -254,6 +260,9 @@ struct scanner
int dropout_color_b;
int buffermode;
int rollerdeskew;
int swdeskew;
int swdespeck;
int swcrop;
int stapledetect;
/* --------------------------------------------------------------------- */
@ -269,6 +278,9 @@ struct scanner
/* the intermediate image params (like user, but possible higher depth) */
struct img_params i;
/* the brightness/contrast LUT for dumb scanners */
unsigned char lut[256];
/* --------------------------------------------------------------------- */
/* values which are set by calibration functions */
int c_res;
@ -528,6 +540,13 @@ static SANE_Status copy_simplex(struct scanner *s, unsigned char * buf, int len,
static SANE_Status copy_duplex(struct scanner *s, unsigned char * buf, int len);
static SANE_Status copy_line(struct scanner *s, unsigned char * buf, int side);
static SANE_Status buffer_despeck(struct scanner *s, int side);
static SANE_Status buffer_deskew(struct scanner *s, int side);
static SANE_Status buffer_crop(struct scanner *s, int side);
static SANE_Status load_lut (unsigned char * lut, int in_bits, int out_bits,
int out_min, int out_max, int slope, int offset);
static SANE_Status read_from_buffer(struct scanner *s, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len, int side);
static SANE_Status image_buffers (struct scanner *s, int setup);