kopia lustrzana https://gitlab.com/sane-project/backends
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
rodzic
4780e307cf
commit
0ea4d7bc4b
|
@ -345,7 +345,7 @@ libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
|
||||||
nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c
|
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_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
|
||||||
libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
|
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
|
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
|
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
|
||||||
|
|
|
@ -1812,7 +1812,7 @@ libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
|
||||||
nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c
|
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_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr
|
||||||
libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS)
|
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_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
|
libcanon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp
|
||||||
nodist_libsane_canon_pp_la_SOURCES = canon_pp-s.c
|
nodist_libsane_canon_pp_la_SOURCES = canon_pp-s.c
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
Section 5 - calibration functions
|
Section 5 - calibration functions
|
||||||
Section 6 - sane_close functions
|
Section 6 - sane_close functions
|
||||||
Section 7 - misc functions
|
Section 7 - misc functions
|
||||||
|
Section 8 - image processing functions
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
v1 2008-10-29, MAN
|
v1 2008-10-29, MAN
|
||||||
|
@ -235,6 +236,11 @@
|
||||||
- correct some debug message
|
- correct some debug message
|
||||||
- better handling of EOF
|
- better handling of EOF
|
||||||
- add intermediate param struct to existing user and scan versions
|
- 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
|
SANE FLOW DIAGRAM
|
||||||
|
|
||||||
|
@ -295,7 +301,7 @@
|
||||||
#include "canon_dr.h"
|
#include "canon_dr.h"
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
#define BUILD 30
|
#define BUILD 33
|
||||||
|
|
||||||
/* values for SANE_DEBUG_CANON_DR env var:
|
/* values for SANE_DEBUG_CANON_DR env var:
|
||||||
- errors 5
|
- errors 5
|
||||||
|
@ -1169,6 +1175,7 @@ init_model (struct scanner *s)
|
||||||
s->duplex_interlace = DUPLEX_INTERLACE_2510;
|
s->duplex_interlace = DUPLEX_INTERLACE_2510;
|
||||||
s->need_ccal = 1;
|
s->need_ccal = 1;
|
||||||
s->need_fcal = 1;
|
s->need_fcal = 1;
|
||||||
|
s->sw_lut = 1;
|
||||||
/*s->invert_tly = 1;*/
|
/*s->invert_tly = 1;*/
|
||||||
|
|
||||||
/*only in Y direction, so we trash them in X*/
|
/*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->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB;
|
||||||
s->duplex_interlace = DUPLEX_INTERLACE_FBFB;
|
s->duplex_interlace = DUPLEX_INTERLACE_FBFB;
|
||||||
s->need_fcal_buffer = 1;
|
s->need_fcal_buffer = 1;
|
||||||
|
s->sw_lut = 1;
|
||||||
|
|
||||||
/*lies*/
|
/*lies*/
|
||||||
s->can_halftone=0;
|
s->can_halftone=0;
|
||||||
|
@ -1881,6 +1889,51 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
|
||||||
opt->cap = SANE_CAP_INACTIVE;
|
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*/
|
/*staple detection*/
|
||||||
if(option==OPT_STAPLEDETECT){
|
if(option==OPT_STAPLEDETECT){
|
||||||
opt->name = "stapledetect";
|
opt->name = "stapledetect";
|
||||||
|
@ -2216,6 +2269,18 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
|
||||||
*val_p = s->rollerdeskew;
|
*val_p = s->rollerdeskew;
|
||||||
return SANE_STATUS_GOOD;
|
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:
|
case OPT_STAPLEDETECT:
|
||||||
*val_p = s->stapledetect;
|
*val_p = s->stapledetect;
|
||||||
return SANE_STATUS_GOOD;
|
return SANE_STATUS_GOOD;
|
||||||
|
@ -2507,6 +2572,18 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
|
||||||
s->rollerdeskew = val_c;
|
s->rollerdeskew = val_c;
|
||||||
return SANE_STATUS_GOOD;
|
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:
|
case OPT_STAPLEDETECT:
|
||||||
s->stapledetect = val_c;
|
s->stapledetect = val_c;
|
||||||
return SANE_STATUS_GOOD;
|
return SANE_STATUS_GOOD;
|
||||||
|
@ -3118,6 +3195,12 @@ sane_start (SANE_Handle handle)
|
||||||
return SANE_STATUS_INVAL;
|
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 */
|
/* batch start? inititalize struct and scanner */
|
||||||
if(!s->started){
|
if(!s->started){
|
||||||
|
|
||||||
|
@ -3141,6 +3224,13 @@ sane_start (SANE_Handle handle)
|
||||||
goto errors;
|
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 */
|
/* AFE cal */
|
||||||
if((ret = calibrate_AFE(s))){
|
if((ret = calibrate_AFE(s))){
|
||||||
DBG (5, "sane_start: ERROR: cannot cal afe\n");
|
DBG (5, "sane_start: ERROR: cannot cal afe\n");
|
||||||
|
@ -3214,6 +3304,13 @@ sane_start (SANE_Handle handle)
|
||||||
goto errors;
|
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 */
|
/* grab next page */
|
||||||
ret = object_position (s, SANE_TRUE);
|
ret = object_position (s, SANE_TRUE);
|
||||||
if (ret != SANE_STATUS_GOOD) {
|
if (ret != SANE_STATUS_GOOD) {
|
||||||
|
@ -3304,14 +3401,11 @@ sane_start (SANE_Handle handle)
|
||||||
DBG (15, "started=%d, side=%d, source=%d\n",
|
DBG (15, "started=%d, side=%d, source=%d\n",
|
||||||
s->started, s->side, s->u.source);
|
s->started, s->side, s->u.source);
|
||||||
|
|
||||||
#if 0
|
|
||||||
s->blocking_mode = 1;
|
|
||||||
|
|
||||||
/* certain options require the entire image to
|
/* certain options require the entire image to
|
||||||
* be collected from the scanner before we can
|
* be collected from the scanner before we can
|
||||||
* tell the user the size of the image. the sane
|
* tell the user the size of the image. the sane
|
||||||
* API has no way to inform the frontend of this,
|
* API has no way to inform the frontend of this,
|
||||||
* so we block. yuck */
|
* so we block and buffer. yuck */
|
||||||
if(s->blocking_mode){
|
if(s->blocking_mode){
|
||||||
|
|
||||||
/* get image */
|
/* get image */
|
||||||
|
@ -3326,10 +3420,14 @@ sane_start (SANE_Handle handle)
|
||||||
goto errors;
|
goto errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finished buffering, adjust image as required */
|
|
||||||
DBG (5, "sane_start: OK: done buffering\n");
|
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);
|
ret = check_for_cancel(s);
|
||||||
s->reading = 0;
|
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*/
|
/*copy the line into the buffer*/
|
||||||
ret = copy_line(s,line,side);
|
ret = copy_line(s,line,side);
|
||||||
if(ret){
|
if(ret){
|
||||||
|
@ -6333,3 +6439,298 @@ sane_get_select_fd (SANE_Handle h, SANE_Int *fdp)
|
||||||
DBG (15, "%p %d\n", h, *fdp);
|
DBG (15, "%p %d\n", h, *fdp);
|
||||||
return SANE_STATUS_UNSUPPORTED;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,9 @@ enum scanner_Option
|
||||||
OPT_DF_THICKNESS,
|
OPT_DF_THICKNESS,
|
||||||
OPT_DF_LENGTH,
|
OPT_DF_LENGTH,
|
||||||
OPT_ROLLERDESKEW,
|
OPT_ROLLERDESKEW,
|
||||||
|
OPT_SWDESKEW,
|
||||||
|
OPT_SWDESPECK,
|
||||||
|
OPT_SWCROP,
|
||||||
OPT_STAPLEDETECT,
|
OPT_STAPLEDETECT,
|
||||||
OPT_DROPOUT_COLOR_F,
|
OPT_DROPOUT_COLOR_F,
|
||||||
OPT_DROPOUT_COLOR_B,
|
OPT_DROPOUT_COLOR_B,
|
||||||
|
@ -185,6 +188,8 @@ struct scanner
|
||||||
int duplex_interlace; /* different models interlace sides differently */
|
int duplex_interlace; /* different models interlace sides differently */
|
||||||
int jpeg_interlace; /* different models interlace jpeg 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 */
|
int reverse_by_mode[6]; /* mode specific */
|
||||||
|
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
|
@ -227,6 +232,7 @@ struct scanner
|
||||||
/*advanced group*/
|
/*advanced group*/
|
||||||
SANE_String_Const compress_list[3];
|
SANE_String_Const compress_list[3];
|
||||||
SANE_Range compress_arg_range;
|
SANE_Range compress_arg_range;
|
||||||
|
SANE_Range swdespeck_range;
|
||||||
SANE_String_Const do_color_list[8];
|
SANE_String_Const do_color_list[8];
|
||||||
|
|
||||||
/*sensor group*/
|
/*sensor group*/
|
||||||
|
@ -235,7 +241,7 @@ struct scanner
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
/* changeable vars to hold user input. modified by SANE_Options above */
|
/* 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 */
|
/* exposed in standard and geometry option groups */
|
||||||
struct img_params u;
|
struct img_params u;
|
||||||
|
|
||||||
|
@ -254,6 +260,9 @@ struct scanner
|
||||||
int dropout_color_b;
|
int dropout_color_b;
|
||||||
int buffermode;
|
int buffermode;
|
||||||
int rollerdeskew;
|
int rollerdeskew;
|
||||||
|
int swdeskew;
|
||||||
|
int swdespeck;
|
||||||
|
int swcrop;
|
||||||
int stapledetect;
|
int stapledetect;
|
||||||
|
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
|
@ -269,6 +278,9 @@ struct scanner
|
||||||
/* the intermediate image params (like user, but possible higher depth) */
|
/* the intermediate image params (like user, but possible higher depth) */
|
||||||
struct img_params i;
|
struct img_params i;
|
||||||
|
|
||||||
|
/* the brightness/contrast LUT for dumb scanners */
|
||||||
|
unsigned char lut[256];
|
||||||
|
|
||||||
/* --------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------- */
|
||||||
/* values which are set by calibration functions */
|
/* values which are set by calibration functions */
|
||||||
int c_res;
|
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_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 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 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);
|
static SANE_Status image_buffers (struct scanner *s, int setup);
|
||||||
|
|
Ładowanie…
Reference in New Issue