summaryrefslogtreecommitdiff
path: root/backend/epjitsu.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/epjitsu.c')
-rw-r--r--backend/epjitsu.c1413
1 files changed, 1000 insertions, 413 deletions
diff --git a/backend/epjitsu.c b/backend/epjitsu.c
index 3e102da..08e78b2 100644
--- a/backend/epjitsu.c
+++ b/backend/epjitsu.c
@@ -123,9 +123,29 @@
- dont export private symbols
v19 2009-08-31, RG
- rewritten calibration routines
- v20 2010-02-09, MAN (SANE 1.0.21 & 1.0.22)
+ v20 2010-02-09, MAN (SANE 1.0.21 to 1.0.24)
- cleanup #include lines & copyright
- add S1300
+ v21 2011-04-15, MAN
+ - unreleased attempt at S1100 support
+ v22 2014-05-15, MAN/Hiroshi Miura
+ - port some S1100 changes from v21
+ - add paper size support
+ v23 2014-05-20, MAN
+ - add S1300i support
+ - fix buffer overruns in read_from_scanner
+ - set default page width
+ - simplified the 225x200 resolution code
+ v24 2014-06-01, MAN
+ - enable fine calibration for S1300i 225 & 300 dpi, and S300 150 dpi
+ v25 2014-06-04, MAN
+ - initial support for fi-65F
+ - initial support for S1100
+ v26 2014-06-28, MAN
+ - add resolution scaling
+ - fix 150 dpi settings for fi-60F and fi-65F
+ - make adf_height_padding variable
+ - make white_factor variable
SANE FLOW DIAGRAM
@@ -174,7 +194,7 @@
#include "epjitsu-cmd.h"
#define DEBUG 1
-#define BUILD 20
+#define BUILD 26
#ifndef MAX3
#define MAX3(a,b,c) ((a) > (b) ? ((a) > (c) ? a : c) : ((b) > (c) ? b : c))
@@ -197,7 +217,6 @@ unsigned char global_firmware_filename[PATH_MAX];
static int coarse_gain_min[3] = { 88, 88, 88 }; /* front, back, FI-60F 3rd plane */
static int coarse_gain_max[3] = { 92, 92, 92 };
static int fine_gain_target[3] = {185, 150, 170}; /* front, back, FI-60F is this ok? */
-static float white_factor[3] = {1.0, 0.93, 0.98}; /* Blue, Red, Green */
/* ------------------------------------------------------------------------- */
#define STRING_FLATBED SANE_I18N("Flatbed")
@@ -458,7 +477,39 @@ attach_one (const char *name)
DBG (15, "attach_one: Found %s scanner %s at %s\n",
s->sane.vendor, s->sane.model, s->sane.name);
- if (strstr (s->sane.model, "S300") || strstr (s->sane.model, "S1300")){
+ if (strstr (s->sane.model, "S1300i")){
+ unsigned char stat;
+
+ DBG (15, "attach_one: Found S1300i\n");
+
+ stat = get_stat(s);
+ if(stat & 0x01){
+ DBG (5, "attach_one: on USB power?\n");
+ s->usb_power=1;
+ }
+
+ s->model = MODEL_S1300i;
+
+ s->has_adf = 1;
+ s->has_adf_duplex = 1;
+ s->min_res = 50;
+ s->max_res = 600;
+ s->adf_height_padding = 600;
+ /* Blue, Red, Green */
+ s->white_factor[0] = 1.0;
+ s->white_factor[1] = 0.93;
+ s->white_factor[2] = 0.98;
+
+ s->source = SOURCE_ADF_FRONT;
+ s->mode = MODE_LINEART;
+ s->resolution = 300;
+ s->page_height = 11.5 * 1200;
+ s->page_width = 8.5 * 1200;
+
+ s->threshold = 120;
+ s->threshold_curve = 55;
+ }
+ else if (strstr (s->sane.model, "S300") || strstr (s->sane.model, "S1300")){
unsigned char stat;
DBG (15, "attach_one: Found S300/S1300\n");
@@ -472,46 +523,93 @@ attach_one (const char *name)
s->model = MODEL_S300;
s->has_adf = 1;
- s->x_res_150 = 1;
- s->x_res_225 = 1;
- s->x_res_300 = 1;
- s->x_res_600 = 1;
- s->y_res_150 = 1;
- s->y_res_225 = 1;
- s->y_res_300 = 1;
- s->y_res_600 = 1;
+ s->has_adf_duplex = 1;
+ s->min_res = 50;
+ s->max_res = 600;
+ s->adf_height_padding = 600;
+ /* Blue, Red, Green */
+ s->white_factor[0] = 1.0;
+ s->white_factor[1] = 0.93;
+ s->white_factor[2] = 0.98;
s->source = SOURCE_ADF_FRONT;
- s->mode = MODE_LINEART;
- s->resolution_x = 300;
+ s->mode = MODE_LINEART;
+ s->resolution = 300;
s->page_height = 11.5 * 1200;
+ s->page_width = 8.5 * 1200;
s->threshold = 120;
s->threshold_curve = 55;
}
+ else if (strstr (s->sane.model, "S1100")){
+ DBG (15, "attach_one: Found S1100\n");
+ s->model = MODEL_S1100;
+
+ s->usb_power = 1;
+ s->has_adf = 1;
+ s->has_adf_duplex = 0;
+ s->min_res = 50;
+ s->max_res = 600;
+ s->adf_height_padding = 450;
+ /* Blue, Red, Green */
+ s->white_factor[0] = 0.95;
+ s->white_factor[1] = 1.0;
+ s->white_factor[2] = 1.0;
+
+ s->source = SOURCE_ADF_FRONT;
+ s->mode = MODE_LINEART;
+ s->resolution = 300;
+ s->page_height = 11.5 * 1200;
+ s->page_width = 8.5 * 1200;
+ s->threshold = 120;
+ s->threshold_curve = 55;
+ }
else if (strstr (s->sane.model, "fi-60F")){
DBG (15, "attach_one: Found fi-60F\n");
s->model = MODEL_FI60F;
s->has_fb = 1;
- s->x_res_150 = 0;
- s->x_res_300 = 1;
- s->x_res_600 = 1;
- s->y_res_150 = 0;
- s->y_res_300 = 1;
- s->y_res_600 = 1;
+ s->min_res = 50;
+ s->max_res = 600;
+ /* Blue, Red, Green */
+ s->white_factor[0] = 1.0;
+ s->white_factor[1] = 0.93;
+ s->white_factor[2] = 0.98;
s->source = SOURCE_FLATBED;
- s->mode = MODE_COLOR;
- s->resolution_x = 300;
+ s->mode = MODE_COLOR;
+ s->resolution = 300;
s->page_height = 5.83 * 1200;
+ s->page_width = 4.1 * 1200;
s->threshold = 120;
s->threshold_curve = 55;
}
+ else if (strstr (s->sane.model, "fi-65F")){
+ DBG (15, "attach_one: Found fi-65F\n");
+
+ s->model = MODEL_FI65F;
+
+ s->has_fb = 1;
+ s->min_res = 50;
+ s->max_res = 600;
+ /* Blue, Red, Green */
+ s->white_factor[0] = 1.0;
+ s->white_factor[1] = 0.93;
+ s->white_factor[2] = 0.98;
+
+ s->source = SOURCE_FLATBED;
+ s->mode = MODE_COLOR;
+ s->resolution = 300;
+ s->page_height = 5.83 * 1200;
+ s->page_width = 4.1 * 1200;
+
+ s->threshold = 120;
+ s->threshold_curve = 55;
+ }
else{
DBG (15, "attach_one: Found other\n");
}
@@ -615,6 +713,7 @@ load_fw (struct scanner *s)
return SANE_STATUS_NO_DOCS;
}
+ /* skip first 256 (=0x100) bytes */
if(lseek(file,0x100,SEEK_SET) != 0x100){
DBG (5, "load_fw: failed to lseek file %s\n",global_firmware_filename);
close(file);
@@ -761,7 +860,7 @@ load_fw (struct scanner *s)
}
/*
- * try to load fw into scanner
+ * get status from scanner
*/
static unsigned char
get_stat(struct scanner *s)
@@ -795,6 +894,10 @@ get_stat(struct scanner *s)
return stat[0];
}
+/*
+ * get scanner identification
+ */
+
static SANE_Status
get_ident(struct scanner *s)
{
@@ -946,8 +1049,10 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
}
if(s->has_adf){
s->source_list[i++]=STRING_ADFFRONT;
- s->source_list[i++]=STRING_ADFBACK;
- s->source_list[i++]=STRING_ADFDUPLEX;
+ if(s->has_adf_duplex){
+ s->source_list[i++]=STRING_ADFBACK;
+ s->source_list[i++]=STRING_ADFDUPLEX;
+ }
}
s->source_list[i]=NULL;
@@ -983,33 +1088,19 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
}
}
- else if(option==OPT_X_RES){
- i=0;
- if(s->x_res_150){
- s->x_res_list[++i] = 150;
- }
- if(s->x_res_225){
- s->x_res_list[++i] = 225;
- }
- if(s->x_res_300){
- s->x_res_list[++i] = 300;
- }
- if(s->x_res_600){
- s->x_res_list[++i] = 600;
- }
- s->x_res_list[0] = i;
-
+ else if(option==OPT_RES){
opt->name = SANE_NAME_SCAN_RESOLUTION;
- opt->title = SANE_TITLE_SCAN_X_RESOLUTION;
- opt->desc = SANE_DESC_SCAN_X_RESOLUTION;
+ opt->title = SANE_TITLE_SCAN_RESOLUTION;
+ opt->desc = SANE_DESC_SCAN_RESOLUTION;
opt->type = SANE_TYPE_INT;
opt->unit = SANE_UNIT_DPI;
- if(i > 1){
- opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- }
+ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- opt->constraint_type = SANE_CONSTRAINT_WORD_LIST;
- opt->constraint.word_list = s->x_res_list;
+ s->res_range.min = s->min_res;
+ s->res_range.max = s->max_res;
+ s->res_range.quant = 1;
+ opt->constraint_type = SANE_CONSTRAINT_RANGE;
+ opt->constraint.range = &s->res_range;
}
/* "Geometry" group ---------------------------------------------------- */
@@ -1056,7 +1147,6 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
opt->constraint_type = SANE_CONSTRAINT_RANGE;
opt->constraint.range = &(s->tl_y_range);
opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
- opt->cap = SANE_CAP_INACTIVE;
}
/* bottom-right x */
@@ -1122,7 +1212,6 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
else{
opt->cap = SANE_CAP_INACTIVE;
}
- opt->cap = SANE_CAP_INACTIVE;
}
/* page height */
@@ -1421,8 +1510,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
}
return SANE_STATUS_GOOD;
- case OPT_X_RES:
- *val_p = s->resolution_x;
+ case OPT_RES:
+ *val_p = s->resolution;
return SANE_STATUS_GOOD;
case OPT_TL_X:
@@ -1569,17 +1658,17 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
s->mode = tmp;
*info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- return change_params(s);
+ return SANE_STATUS_GOOD;
- case OPT_X_RES:
+ case OPT_RES:
- if (s->resolution_x == val_c)
+ if (s->resolution == val_c)
return SANE_STATUS_GOOD;
- s->resolution_x = val_c;
+ s->resolution = val_c;
*info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- return change_params(s);
+ return SANE_STATUS_GOOD;
/* Geometry Group */
case OPT_TL_X:
@@ -1598,7 +1687,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option,
s->tl_y = FIXED_MM_TO_SCANNER_UNIT(val_c);
*info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- return SANE_STATUS_GOOD;
+ return change_params(s);
case OPT_BR_X:
if (s->br_x == FIXED_MM_TO_SCANNER_UNIT(val_c))
@@ -1685,16 +1774,15 @@ struct model_res {
int max_y;
int min_y;
- int act_width; /* total data width output, in pixels per side (always 3 sides) */
- int req_width; /* stride in pixels per side between color planes (always 3 sides) */
- int head_width;
- int pad_width;
+ int line_stride; /* byte width of 1 raw side, with padding */
+ int plane_stride; /* byte width of 1 raw color plane, with padding */
+ int plane_width; /* byte width of 1 raw color plane, without padding */
int block_height;
- int cal_width;
- int cal_headwidth;
- int cal_reqwidth;
+ int cal_line_stride;
+ int cal_plane_stride;
+ int cal_plane_width;
unsigned char * sw_coarsecal;
unsigned char * sw_finecal;
@@ -1709,67 +1797,141 @@ struct model_res {
static struct model_res settings[] = {
/*S300 AC*/
-/* model xres yres u mxx mnx mxy mny actw reqw hedw padw bh calw cal_hedw cal_reqw */
- { MODEL_S300, 150, 150, 0, 1296, 32, 2662, 32, 4256, 1480, 1296, 184, 41, 8512, 2592, 2960,
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_S300, 150, 150, 0, 1296, 32, 2662, 32, 4256*3, 1480*3, 1296, 41, 8512*3, 2960*3, 2592,
setWindowCoarseCal_S300_150, setWindowFineCal_S300_150,
setWindowSendCal_S300_150, sendCal1Header_S300_150,
sendCal2Header_S300_150, setWindowScan_S300_150 },
- { MODEL_S300, 225, 200, 0, 1944, 32, 3993, 32, 6144, 2100, 1944, 156, 28, 8192, 2592, 2800,
+ { MODEL_S300, 225, 200, 0, 1944, 32, 3993, 32, 6144*3, 2100*3, 1944, 28, 8192*3, 2800*3, 2592,
setWindowCoarseCal_S300_225, setWindowFineCal_S300_225,
setWindowSendCal_S300_225, sendCal1Header_S300_225,
sendCal2Header_S300_225, setWindowScan_S300_225 },
- { MODEL_S300, 300, 300, 0, 2592, 32, 5324, 32, 8192, 2800, 2592, 208, 21, 8192, 2592, 2800,
+ { MODEL_S300, 300, 300, 0, 2592, 32, 5324, 32, 8192*3, 2800*3, 2592, 21, 8192*3, 2800*3, 2592,
setWindowCoarseCal_S300_300, setWindowFineCal_S300_300,
setWindowSendCal_S300_300, sendCal1Header_S300_300,
sendCal2Header_S300_300, setWindowScan_S300_300 },
- { MODEL_S300, 600, 600, 0, 5184, 32, 10648, 32, 16064, 5440, 5184, 256, 10, 16064, 5184, 5440,
+ { MODEL_S300, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184,
setWindowCoarseCal_S300_600, setWindowFineCal_S300_600,
setWindowSendCal_S300_600, sendCal1Header_S300_600,
sendCal2Header_S300_600, setWindowScan_S300_600 },
/*S300 USB*/
-/* model xres yres u mxx mnx mxy mny actw reqw hedw padw bh calw cal_hedw cal_reqw */
- { MODEL_S300, 150, 150, 1, 1296, 32, 2662, 32, 7216, 2960, 1296, 1664, 24, 14432, 2592, 5920,
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_S300, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592,
setWindowCoarseCal_S300_150_U, setWindowFineCal_S300_150_U,
setWindowSendCal_S300_150_U, sendCal1Header_S300_150_U,
sendCal2Header_S300_150_U, setWindowScan_S300_150_U },
- { MODEL_S300, 225, 200, 1, 1944, 32, 3993, 32, 10584, 4320, 1944, 2376, 16, 14112, 2592, 5760,
+ { MODEL_S300, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592,
setWindowCoarseCal_S300_225_U, setWindowFineCal_S300_225_U,
setWindowSendCal_S300_225_U, sendCal1Header_S300_225_U,
sendCal2Header_S300_225_U, setWindowScan_S300_225_U },
- { MODEL_S300, 300, 300, 1, 2592, 32, 5324, 32, 15872, 6640, 2592, 4048, 11, 15872, 2592, 6640,
+ { MODEL_S300, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592,
setWindowCoarseCal_S300_300_U, setWindowFineCal_S300_300_U,
setWindowSendCal_S300_300_U, sendCal1Header_S300_300_U,
sendCal2Header_S300_300_U, setWindowScan_S300_300_U },
- { MODEL_S300, 600, 600, 1, 5184, 32, 10648, 32, 16064, 5440, 5184, 256, 10, 16064, 5184, 5440,
+ { MODEL_S300, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184,
+ setWindowCoarseCal_S300_600, setWindowFineCal_S300_600,
+ setWindowSendCal_S300_600, sendCal1Header_S300_600,
+ sendCal2Header_S300_600, setWindowScan_S300_600 },
+
+ /*S1300i AC*/
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_S1300i, 150, 150, 0, 1296, 32, 2662, 32, 4016*3, 1360*3, 1296, 43, 8032*3, 2720*3, 2592,
+ setWindowCoarseCal_S1300i_150, setWindowFineCal_S1300i_150,
+ setWindowSendCal_S1300i_150, sendCal1Header_S1300i_150,
+ sendCal2Header_S1300i_150, setWindowScan_S1300i_150 },
+
+ { MODEL_S1300i, 225, 200, 0, 1944, 32, 3993, 32, 6072*3, 2063*3, 1944, 28, 8096*3, 2752*3, 2592,
+ setWindowCoarseCal_S1300i_225, setWindowFineCal_S1300i_225,
+ setWindowSendCal_S1300i_225, sendCal1Header_S1300i_225,
+ sendCal2Header_S1300i_225, setWindowScan_S1300i_225 },
+
+ { MODEL_S1300i, 300, 300, 0, 2592, 32, 5324, 32, 8096*3, 2751*3, 2592, 21, 8096*3, 2752*3, 2592,
+ setWindowCoarseCal_S1300i_300, setWindowFineCal_S1300i_300,
+ setWindowSendCal_S1300i_300, sendCal1Header_S1300i_300,
+ sendCal2Header_S1300i_300, setWindowScan_S1300i_300 },
+
+ /*NOTE: S1300i uses S300 data blocks for remainder*/
+ { MODEL_S1300i, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184,
setWindowCoarseCal_S300_600, setWindowFineCal_S300_600,
setWindowSendCal_S300_600, sendCal1Header_S300_600,
sendCal2Header_S300_600, setWindowScan_S300_600 },
+ /*S1300i USB*/
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_S1300i, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592,
+ setWindowCoarseCal_S300_150_U, setWindowFineCal_S300_150_U,
+ setWindowSendCal_S300_150_U, sendCal1Header_S1300i_USB,
+ sendCal2Header_S1300i_USB, setWindowScan_S300_150_U },
+
+ { MODEL_S1300i, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592,
+ setWindowCoarseCal_S300_225_U, setWindowFineCal_S300_225_U,
+ setWindowSendCal_S300_225_U, sendCal1Header_S1300i_USB,
+ sendCal2Header_S1300i_USB, setWindowScan_S300_225_U },
+
+ { MODEL_S1300i, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592,
+ setWindowCoarseCal_S300_300_U, setWindowFineCal_S300_300_U,
+ setWindowSendCal_S300_300_U, sendCal1Header_S1300i_USB,
+ sendCal2Header_S1300i_USB, setWindowScan_S300_300_U },
+
+ { MODEL_S1300i, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184,
+ setWindowCoarseCal_S300_600, setWindowFineCal_S300_600,
+ setWindowSendCal_S300_600, sendCal1Header_S1300i_USB,
+ sendCal2Header_S1300i_USB, setWindowScan_S300_600 },
+
/*fi-60F*/
-/* model xres yres u mxx mnx mxy mny actw reqw hedw padw bh calw cal_hedw cal_reqw */
- { MODEL_FI60F, 150, 150, 0, 648, 32, 875, 32, 1480, 632, 216, 416, 41, 1480, 216, 632,
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_FI60F, 300, 150, 0, 1296, 32, 875, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432,
+ setWindowCoarseCal_FI60F_150, setWindowFineCal_FI60F_150,
+ setWindowSendCal_FI60F_150, sendCal1Header_FI60F_150,
+ sendCal2Header_FI60F_150, setWindowScan_FI60F_150 },
+
+ { MODEL_FI60F, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432,
+ setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300,
+ setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300,
+ sendCal2Header_FI60F_300, setWindowScan_FI60F_300 },
+
+ { MODEL_FI60F, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864,
+ setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600,
+ setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600,
+ sendCal2Header_FI60F_600, setWindowScan_FI60F_600 },
+
+ /*fi-65F*/
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_FI65F, 300, 150, 0, 1296, 32, 875, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432,
setWindowCoarseCal_FI60F_150, setWindowFineCal_FI60F_150,
setWindowSendCal_FI60F_150, sendCal1Header_FI60F_150,
sendCal2Header_FI60F_150, setWindowScan_FI60F_150 },
- { MODEL_FI60F, 300, 300, 0, 1296, 32, 1749, 32, 2400, 958, 432, 526, 72, 2400, 432, 958,
+ { MODEL_FI65F, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432,
setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300,
setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300,
sendCal2Header_FI60F_300, setWindowScan_FI60F_300 },
- { MODEL_FI60F, 600, 600, 0, 2592, 32, 3498, 32, 2848, 978, 864, 114, 61, 2848, 864, 978,
+ { MODEL_FI65F, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864,
setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600,
setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600,
sendCal2Header_FI60F_600, setWindowScan_FI60F_600 },
- { MODEL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /*S1100 USB*/
+/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */
+ { MODEL_S1100, 300, 300, 1, 2592, 32, 5324, 32, 8912, 3160, 2592, 58, 8912, 3160, 2592,
+ setWindowCoarseCal_S1100_300_U, setWindowFineCal_S1100_300_U,
+ setWindowSendCal_S1100_300_U, sendCal1Header_S1100_300_U,
+ sendCal2Header_S1100_300_U, setWindowScan_S1100_300_U },
+
+ { MODEL_S1100, 600, 600, 1, 5184, 32, 10648, 32, 15904, 5360, 5184, 32, 15904, 5360, 5184,
+ setWindowCoarseCal_S1100_600_U, setWindowFineCal_S1100_600_U,
+ setWindowSendCal_S1100_600_U, sendCal1Header_S1100_600_U,
+ sendCal2Header_S1100_600_U, setWindowScan_S1100_600_U },
+
+ { MODEL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
NULL, NULL, NULL, NULL, NULL, NULL },
};
@@ -1789,86 +1951,130 @@ change_params(struct scanner *s)
do {
if(settings[i].model == s->model
- && settings[i].x_res == s->resolution_x
- && settings[i].usb_power == s->usb_power){
-
- /*pull in closest y resolution*/
- s->resolution_y = settings[i].y_res;
-
- /*1200 dpi*/
- s->max_x = settings[i].max_x * 1200/s->resolution_x;
- s->min_x = settings[i].min_x * 1200/s->resolution_x;
- s->max_y = settings[i].max_y * 1200/s->resolution_y;
- s->min_y = settings[i].min_y * 1200/s->resolution_y;
+ && settings[i].x_res >= s->resolution
+ && settings[i].y_res >= s->resolution
+ && settings[i].usb_power == s->usb_power
+ ){
+ break;
+ }
+ i++;
+ } while (settings[i].model);
- s->page_width = s->max_x;
- s->br_x = s->max_x;
- s->br_y = s->max_y;
+ if (!settings[i].model){
+ return SANE_STATUS_INVAL;
+ }
- /*current dpi*/
- s->setWindowCoarseCal = settings[i].sw_coarsecal;
- s->setWindowCoarseCalLen = SET_WINDOW_LEN;
+ /*1200 dpi*/
+ s->max_x = PIX_TO_SCANNER_UNIT( settings[i].max_x, settings[i].x_res );
+ s->min_x = PIX_TO_SCANNER_UNIT( settings[i].min_x, settings[i].x_res );
+ s->max_y = PIX_TO_SCANNER_UNIT( settings[i].max_y, settings[i].y_res );
+ s->min_y = PIX_TO_SCANNER_UNIT( settings[i].min_y, settings[i].y_res );
- s->setWindowFineCal = settings[i].sw_finecal;
- s->setWindowFineCalLen = SET_WINDOW_LEN;
+ /* wrong place for this?*/
+ s->page_width = s->max_x;
+ s->br_x = s->max_x;
+ s->br_y = s->max_y;
- s->setWindowSendCal = settings[i].sw_sendcal;
- s->setWindowSendCalLen = SET_WINDOW_LEN;
+ /*current dpi*/
+ s->setWindowCoarseCal = settings[i].sw_coarsecal;
+ s->setWindowCoarseCalLen = SET_WINDOW_LEN;
- s->sendCal1Header = settings[i].head_cal1;
- s->sendCal1HeaderLen = 14;
+ s->setWindowFineCal = settings[i].sw_finecal;
+ s->setWindowFineCalLen = SET_WINDOW_LEN;
- s->sendCal2Header = settings[i].head_cal2;
- s->sendCal2HeaderLen = 7;
+ s->setWindowSendCal = settings[i].sw_sendcal;
+ s->setWindowSendCalLen = SET_WINDOW_LEN;
- s->setWindowScan = settings[i].sw_scan;
- s->setWindowScanLen = SET_WINDOW_LEN;
+ s->sendCal1Header = settings[i].head_cal1;
+ s->sendCal1HeaderLen = 14;
- break;
- }
- i++;
- } while (settings[i].model);
+ s->sendCal2Header = settings[i].head_cal2;
+ s->sendCal2HeaderLen = 7;
- if (!settings[i].model)
- {
- return SANE_STATUS_INVAL;
- }
+ s->setWindowScan = settings[i].sw_scan;
+ s->setWindowScanLen = SET_WINDOW_LEN;
- if (s->model == MODEL_S300)
+ if (s->model == MODEL_S300 || s->model == MODEL_S1300i)
{
img_heads = 1; /* image width is the same as the plane width on the S300 */
img_pages = 2;
}
- else /* (s->model == MODEL_FI60F) */
+ else if (s->model == MODEL_S1100)
+ {
+ img_heads = 1; /* image width is the same as the plane width on the S1000 */
+ img_pages = 1;
+ }
+ else /* MODEL_FI60F or MODEL_FI65F */
{
img_heads = 3; /* image width is 3* the plane width on the FI-60F */
img_pages = 1;
}
+
+ /* height */
+ if (s->tl_y > s->max_y - s->min_y)
+ s->tl_y = s->max_y - s->min_y - s->adf_height_padding;
+ if (s->tl_y + s->page_height > s->max_y - s->adf_height_padding)
+ s->page_height = s->max_y - s->adf_height_padding - s->tl_y;
+ if (s->page_height < s->min_y && s->page_height > 0)
+ s->page_height = s->min_y;
+ if (s->tl_y + s->page_height > s->max_y)
+ s->tl_y = s->max_y - s->adf_height_padding - s->page_height ;
+
+ if (s->page_height > 0) {
+ s->br_y = s->tl_y + s->page_height;
+ }
+ else
+ {
+ s->br_y = s->max_y;
+ }
+
+ /*width*/
+ if (s->page_width > s->max_x)
+ s->page_width = s->max_x;
+ else if (s->page_width < s->min_x)
+ s->page_width = s->min_x;
+ s->tl_x = (s->max_x - s->page_width)/2;
+ s->br_x = (s->max_x + s->page_width)/2;
- /* set up the transfer structs */
- s->cal_image.plane_width = settings[i].cal_headwidth;
- s->cal_image.plane_stride = settings[i].cal_reqwidth * 3;
- s->cal_image.line_stride = settings[i].cal_width * 3;
+ /*=============================================================*/
+ /* set up the calibration structs */
+ /* generally full width, short height, full resolution */
+ s->cal_image.line_stride = settings[i].cal_line_stride;
+ s->cal_image.plane_stride = settings[i].cal_plane_stride;
+ s->cal_image.plane_width = settings[i].cal_plane_width;
+ s->cal_image.x_res = settings[i].x_res;
+ s->cal_image.y_res = settings[i].y_res;
s->cal_image.raw_data = NULL;
s->cal_image.image = NULL;
- s->cal_data.plane_width = settings[i].cal_headwidth; /* width is the same, but there are 2 bytes per pixel component */
- s->cal_data.plane_stride = settings[i].cal_reqwidth * 6;
- s->cal_data.line_stride = settings[i].cal_width * 6;
+ /* width is the same, but there are 2 bytes per pixel component */
+ s->cal_data.line_stride = settings[i].cal_line_stride * 2;
+ s->cal_data.plane_stride = settings[i].cal_plane_stride * 2;
+ s->cal_data.plane_width = settings[i].cal_plane_width;
+ s->cal_data.x_res = settings[i].x_res;
+ s->cal_data.y_res = settings[i].y_res;
s->cal_data.raw_data = NULL;
s->cal_data.image = &s->sendcal;
- s->block_xfr.plane_width = settings[i].head_width;
- s->block_xfr.plane_stride = settings[i].req_width * 3;
- s->block_xfr.line_stride = settings[i].act_width * 3;
+ /*=============================================================*/
+ /* set up the input scan structs */
+ s->block_xfr.line_stride = settings[i].line_stride;
+ s->block_xfr.plane_stride = settings[i].plane_stride;
+ s->block_xfr.plane_width = settings[i].plane_width;
+ s->block_xfr.x_res = settings[i].x_res;
+ s->block_xfr.y_res = settings[i].y_res;
s->block_xfr.raw_data = NULL;
s->block_xfr.image = &s->block_img;
/* set up the block image used during scanning operation */
- width = s->block_xfr.plane_width * img_heads;
+ /* note that this is the same width/x_res as the final output image */
+ /* but the height/y_res are the same as block_xfr */
+ width = (s->block_xfr.plane_width*s->resolution/settings[i].x_res) * img_heads;
s->block_img.width_pix = width;
s->block_img.width_bytes = width * 3;
s->block_img.height = settings[i].block_height;
+ s->block_img.x_res = s->resolution;
+ s->block_img.y_res = settings[i].y_res;
s->block_img.pages = img_pages;
s->block_img.buffer = NULL;
@@ -1877,6 +2083,8 @@ change_params(struct scanner *s)
s->coarsecal.width_pix = s->darkcal.width_pix = s->lightcal.width_pix = width;
s->coarsecal.width_bytes = s->darkcal.width_bytes = s->lightcal.width_bytes = width * 3;
s->coarsecal.height = 1;
+ s->coarsecal.x_res = s->darkcal.x_res = s->lightcal.x_res = settings[i].x_res;
+ s->coarsecal.y_res = s->darkcal.y_res = s->lightcal.y_res = settings[i].y_res;
s->darkcal.height = s->lightcal.height = 16;
s->coarsecal.pages = s->darkcal.pages = s->lightcal.pages = img_pages;
s->coarsecal.buffer = s->darkcal.buffer = s->lightcal.buffer = NULL;
@@ -1886,50 +2094,95 @@ change_params(struct scanner *s)
s->sendcal.width_pix = width;
s->sendcal.width_bytes = width * 6; /* 2 bytes of cal data per pixel component */
s->sendcal.height = 1;
+ s->sendcal.x_res = settings[i].x_res;
+ s->sendcal.y_res = settings[i].y_res;
s->sendcal.pages = img_pages;
s->sendcal.buffer = NULL;
/* set up the fullscan parameters */
s->fullscan.width_bytes = s->block_xfr.line_stride;
+ s->fullscan.x_res = settings[i].x_res;
+ s->fullscan.y_res = settings[i].y_res;
if(s->source == SOURCE_FLATBED || !s->page_height)
{
/* flatbed and adf in autodetect always ask for all*/
- s->fullscan.height = s->max_y * s->resolution_y / 1200;
+ s->fullscan.height = SCANNER_UNIT_TO_PIX(s->max_y, s->fullscan.y_res);
}
else
{
- /* adf with specified paper size requires padding (~1/2in) */
- s->fullscan.height = (s->page_height+600) * s->resolution_y / 1200;
+ /* adf with specified paper size requires padding on top of page_height (~1/2in) */
+ s->fullscan.height = SCANNER_UNIT_TO_PIX((s->page_height + s->tl_y + s->adf_height_padding), s->fullscan.y_res);
}
- /* fill in front settings */
+ /*=============================================================*/
+ /* set up the output image structs */
+ /* output image might be different from scan due to interpolation */
+ s->front.x_res = s->resolution;
+ s->front.y_res = s->resolution;
+ if(s->source == SOURCE_FLATBED)
+ {
+ /* flatbed ignores the tly */
+ s->front.height = SCANNER_UNIT_TO_PIX(s->max_y - s->tl_y, s->front.y_res);
+ }
+ else if(!s->page_height)
+ {
+ /* adf in autodetect always asks for all */
+ s->front.height = SCANNER_UNIT_TO_PIX(s->max_y, s->front.y_res);
+ }
+ else
+ {
+ /* adf with specified paper size */
+ s->front.height = SCANNER_UNIT_TO_PIX(s->page_height, s->front.y_res);
+ }
s->front.width_pix = s->block_img.width_pix;
+ s->front.x_start_offset = (s->block_xfr.image->width_pix - s->front.width_pix)/2;
switch (s->mode) {
case MODE_COLOR:
s->front.width_bytes = s->front.width_pix*3;
+ s->front.x_offset_bytes = s->front.x_start_offset *3;
break;
case MODE_GRAYSCALE:
s->front.width_bytes = s->front.width_pix;
+ s->front.x_offset_bytes = s->front.x_start_offset;
break;
default: /*binary*/
s->front.width_bytes = s->front.width_pix/8;
+ s->front.width_pix = s->front.width_bytes * 8;
+ /*s->page_width = PIX_TO_SCANNER_UNIT(s->front.width_pix, (img_heads * s->resolution_x));*/
+ s->front.x_offset_bytes = s->front.x_start_offset/8;
break;
}
- /*output image might be taller than scan due to interpolation*/
- s->front.height = s->fullscan.height * s->resolution_x / s->resolution_y;
+
+ /* ADF front need to remove padding header */
+ if (s->source != SOURCE_FLATBED)
+ {
+ s->front.y_skip_offset = SCANNER_UNIT_TO_PIX(s->tl_y+s->adf_height_padding, s->fullscan.y_res);
+ }
+ else
+ {
+ s->front.y_skip_offset = SCANNER_UNIT_TO_PIX(s->tl_y, s->fullscan.y_res);
+ }
+
s->front.pages = 1;
s->front.buffer = NULL;
/* back settings always same as front settings */
s->back.width_pix = s->front.width_pix;
s->back.width_bytes = s->front.width_bytes;
+ s->back.x_res = s->front.x_res;
+ s->back.y_res = s->front.y_res;
s->back.height = s->front.height;
+ s->back.x_start_offset = s->front.x_start_offset;
+ s->back.x_offset_bytes = s->front.x_offset_bytes;
+ s->back.y_skip_offset = SCANNER_UNIT_TO_PIX(s->tl_y, s->fullscan.y_res);
s->back.pages = 1;
s->back.buffer = NULL;
/* dynamic threshold temp buffer, in gray */
s->dt.width_pix = s->front.width_pix;
s->dt.width_bytes = s->front.width_pix;
+ s->dt.x_res = s->front.x_res;
+ s->dt.y_res = s->front.y_res;
s->dt.height = 1;
s->dt.pages = 1;
s->dt.buffer = NULL;
@@ -2120,7 +2373,7 @@ sane_start (SANE_Handle handle)
/* ingest paper with adf */
if( s->source == SOURCE_ADF_BACK || s->source == SOURCE_ADF_FRONT
|| (s->source == SOURCE_ADF_DUPLEX && s->side == SIDE_FRONT) ){
- ret = ingest(s);
+ ret = object_position(s,EPJITSU_PAPER_INGEST);
if (ret != SANE_STATUS_GOOD) {
DBG (5, "sane_start: ERROR: failed to ingest\n");
sane_cancel((SANE_Handle)s);
@@ -2222,6 +2475,9 @@ sane_start (SANE_Handle handle)
s->pages[i].bytes_total = page_img->width_bytes * page_img->height;
s->pages[i].bytes_scanned = 0;
s->pages[i].bytes_read = 0;
+ s->pages[i].lines_rx = 0;
+ s->pages[i].lines_pass = 0;
+ s->pages[i].lines_tx = 0;
s->pages[i].done = 0;
}
@@ -2343,43 +2599,123 @@ setup_buffers(struct scanner *s)
*/
static SANE_Status
-coarsecal(struct scanner *s)
+coarsecal_send_cal(struct scanner *s, unsigned char *pay)
{
SANE_Status ret = SANE_STATUS_GOOD;
-
- size_t cmdLen = 2;
unsigned char cmd[2];
-
- size_t statLen = 1;
unsigned char stat[1];
+ size_t cmdLen,statLen,payLen;
+
+ DBG (5, "coarsecal_send_cal: start\n");
+ /* send coarse cal (c6) */
+ cmd[0] = 0x1b;
+ cmd[1] = 0xc6;
+ cmdLen = 2;
+ stat[0] = 0;
+ statLen = 1;
+
+ ret = do_cmd(
+ s, 0,
+ cmd, cmdLen,
+ NULL, 0,
+ stat, &statLen
+ );
+ if(ret){
+ DBG (5, "coarsecal_send_cal: error sending c6 cmd\n");
+ return ret;
+ }
+ if(stat[0] != 6){
+ DBG (5, "coarsecal_send_cal: cmd bad c6 status?\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ /*send coarse cal payload*/
+ stat[0] = 0;
+ statLen = 1;
+ payLen = 28;
- size_t payLen = 28;
- unsigned char pay[28];
+ ret = do_cmd(
+ s, 0,
+ pay, payLen,
+ NULL, 0,
+ stat, &statLen
+ );
+ if(ret){
+ DBG (5, "coarsecal_send_cal: error sending c6 payload\n");
+ return ret;
+ }
+ if(stat[0] != 6){
+ DBG (5, "coarsecal_send_cal: c6 payload bad status?\n");
+ return SANE_STATUS_IO_ERROR;
+ }
- int try_count, cal_good[2], x, i, j;
- int param[2], zcount[2], high_param[2], low_param[2], avg[2], maxval[2];
- int rgb_avg[2][3], rgb_hicount[2][3];
+ DBG (5, "coarsecal_send_cal: finish\n");
+ return ret;
+}
- DBG (10, "coarsecal: start\n");
+static SANE_Status
+coarsecal_get_line(struct scanner *s, struct image *img)
+{
+ SANE_Status ret = SANE_STATUS_GOOD;
+ unsigned char cmd[2];
+ unsigned char stat[1];
+ size_t cmdLen,statLen;
- if(s->model == MODEL_S300){
- memcpy(pay,coarseCalData_S300,payLen);
- }
- else{
- memcpy(pay,coarseCalData_FI60F,payLen);
- }
+ DBG (5, "coarsecal_get_line: start\n");
- /* ask for 1 line */
- ret = set_window(s, WINDOW_COARSECAL);
+ /* send scan d2 command */
+ cmd[0] = 0x1b;
+ cmd[1] = 0xd2;
+ cmdLen = 2;
+ stat[0] = 0;
+ statLen = 1;
+
+ ret = do_cmd(
+ s, 0,
+ cmd, cmdLen,
+ NULL, 0,
+ stat, &statLen
+ );
if(ret){
- DBG (5, "coarsecal: error sending setwindow\n");
+ DBG (5, "coarsecal_get_line: error sending d2 cmd\n");
return ret;
}
+ if(stat[0] != 6){
+ DBG (5, "coarsecal_get_line: cmd bad d2 status?\n");
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ s->cal_image.image = img;
+ update_transfer_totals(&s->cal_image);
+
+ while(!s->cal_image.done){
+ ret = read_from_scanner(s,&s->cal_image);
+ if(ret){
+ DBG (5, "coarsecal_get_line: cant read from scanner\n");
+ return ret;
+ }
+ }
+ /* convert the raw data into normal packed pixel data */
+ descramble_raw(s, &s->cal_image);
+
+ DBG (5, "coarsecal_get_line: finish\n");
+ return ret;
+}
+
+static SANE_Status
+coarsecal_dark(struct scanner *s, unsigned char *pay)
+{
+ SANE_Status ret = SANE_STATUS_GOOD;
+
+ int try_count, cal_good[2], x, j;
+ int param[2], zcount[2], high_param[2], low_param[2], avg[2], maxval[2];
+
+ DBG (5, "coarsecal_dark: start\n");
/* dark cal, lamp off */
ret = lamp(s,0);
if(ret){
- DBG (5, "coarsecal: error lamp off\n");
+ DBG (5, "coarsecal_dark: error lamp off\n");
return ret;
}
@@ -2394,93 +2730,23 @@ coarsecal(struct scanner *s)
try_count--;
/* update the coarsecal payload to use our new dark offset parameters */
- if (s->model == MODEL_S300)
+ if (s->model == MODEL_S300 || s->model == MODEL_S1300i)
{
pay[5] = param[0];
pay[7] = param[1];
}
- else /* (s->model == MODEL_FI60F) */
+ else /* MODEL_S1100 or MODEL_FI60F or MODEL_FI65F */
{
pay[5] = param[0];
pay[7] = param[0];
pay[9] = param[0];
}
- /* send coarse cal (c6) */
- cmd[0] = 0x1b;
- cmd[1] = 0xc6;
- stat[0] = 0;
- statLen = 1;
-
- ret = do_cmd(
- s, 0,
- cmd, cmdLen,
- NULL, 0,
- stat, &statLen
- );
- if(ret){
- DBG (5, "coarsecal: error sending c6 cmd\n");
- return ret;
- }
- if(stat[0] != 6){
- DBG (5, "coarsecal: cmd bad c6 status?\n");
- return SANE_STATUS_IO_ERROR;
- }
-
- /*send coarse cal payload*/
- stat[0] = 0;
- statLen = 1;
-
- ret = do_cmd(
- s, 0,
- pay, payLen,
- NULL, 0,
- stat, &statLen
- );
- if(ret){
- DBG (5, "coarsecal: error sending c6 payload\n");
- return ret;
- }
- if(stat[0] != 6){
- DBG (5, "coarsecal: c6 payload bad status?\n");
- return SANE_STATUS_IO_ERROR;
- }
+ ret = coarsecal_send_cal(s, pay);
- DBG(15, "coarsecal offset: parameter front: %i back: %i\n", param[0], param[1]);
+ DBG(15, "coarsecal_dark offset: parameter front: %i back: %i\n", param[0], param[1]);
- /* send scan d2 command */
- cmd[0] = 0x1b;
- cmd[1] = 0xd2;
- stat[0] = 0;
- statLen = 1;
-
- ret = do_cmd(
- s, 0,
- cmd, cmdLen,
- NULL, 0,
- stat, &statLen
- );
- if(ret){
- DBG (5, "coarsecal: error sending d2 cmd\n");
- return ret;
- }
- if(stat[0] != 6){
- DBG (5, "coarsecal: cmd bad d2 status?\n");
- return SANE_STATUS_IO_ERROR;
- }
-
- s->cal_image.image = &s->coarsecal;
- update_transfer_totals(&s->cal_image);
-
- while(!s->cal_image.done){
- ret = read_from_scanner(s,&s->cal_image);
- if(ret){
- DBG (5, "coarsecal: cant read from scanner\n");
- return ret;
- }
- }
- /* convert the raw data into normal packed pixel data */
- descramble_raw(s, &s->cal_image);
+ ret = coarsecal_get_line(s, &s->coarsecal);
/* gather statistics: count the proportion of 0-valued pixels */
/* since the lamp is off, there's no point in looking at the green or blue data - they're all from the same sensor anyway */
@@ -2504,9 +2770,9 @@ coarsecal(struct scanner *s)
avg[j] /= s->coarsecal.width_bytes;
zcount[j] = zcount[j] * 1000 / s->coarsecal.width_bytes;
}
- DBG(15, "coarsecal offset: average pixel values front: %i back: %i\n", avg[0], avg[1]);
- DBG(15, "coarsecal offset: maximum pixel values front: %i back: %i\n", maxval[0], maxval[1]);
- DBG(15, "coarsecal offset: 0-valued pixel count front: %f%% back: %f%%\n", zcount[0] / 10.0f, zcount[1] / 10.0f);
+ DBG(15, "coarsecal_dark offset: average pixel values front: %i back: %i\n", avg[0], avg[1]);
+ DBG(15, "coarsecal_dark offset: maximum pixel values front: %i back: %i\n", maxval[0], maxval[1]);
+ DBG(15, "coarsecal_dark offset: 0-valued pixel count front: %f%% back: %f%%\n", zcount[0] / 10.0f, zcount[1] / 10.0f);
/* check the values, adjust parameters if they are not within the target range */
for (j = 0; j < s->coarsecal.pages; j++)
@@ -2530,10 +2796,25 @@ coarsecal(struct scanner *s)
} /* continue looping for up to 8 tries */
+ DBG (5, "coarsecal_dark: finish\n");
+ return ret;
+}
+
+static SANE_Status
+coarsecal_light(struct scanner *s, unsigned char *pay)
+{
+ SANE_Status ret = SANE_STATUS_GOOD;
+
+ int try_count, cal_good[2], x, i, j;
+ int param[2], zcount[2], high_param[2], low_param[2], avg[2];
+ int rgb_avg[2][3], rgb_hicount[2][3];
+
+ DBG (5, "coarsecal_light: start\n");
+
/* light cal, lamp on */
ret = lamp(s,1);
if(ret){
- DBG (5, "coarsecal: error lamp on\n");
+ DBG (5, "coarsecal_light: error lamp on\n");
return ret;
}
@@ -2547,82 +2828,12 @@ coarsecal(struct scanner *s)
while (try_count > 0){
try_count--;
- /* send coarse cal (c6) */
- cmd[0] = 0x1b;
- cmd[1] = 0xc6;
- stat[0] = 0;
- statLen = 1;
-
- ret = do_cmd(
- s, 0,
- cmd, cmdLen,
- NULL, 0,
- stat, &statLen
- );
- if(ret){
- DBG (5, "coarsecal: error sending c6 cmd\n");
- return ret;
- }
- if(stat[0] != 6){
- DBG (5, "coarsecal: cmd bad c6 status?\n");
- return SANE_STATUS_IO_ERROR;
- }
-
- /*send coarse cal payload*/
- stat[0] = 0;
- statLen = 1;
-
- ret = do_cmd(
- s, 0,
- pay, payLen,
- NULL, 0,
- stat, &statLen
- );
- if(ret){
- DBG (5, "coarsecal: error sending c6 payload\n");
- return ret;
- }
- if(stat[0] != 6){
- DBG (5, "coarsecal: c6 payload bad status?\n");
- return SANE_STATUS_IO_ERROR;
- }
+ ret = coarsecal_send_cal(s, pay);
- DBG(15, "coarsecal gain: parameter front: %i back: %i\n", param[0], param[1]);
+ DBG(15, "coarsecal_light gain: parameter front: %i back: %i\n", param[0], param[1]);
- /* send scan d2 command */
- cmd[0] = 0x1b;
- cmd[1] = 0xd2;
- stat[0] = 0;
- statLen = 1;
+ ret = coarsecal_get_line(s, &s->coarsecal);
- ret = do_cmd(
- s, 0,
- cmd, cmdLen,
- NULL, 0,
- stat, &statLen
- );
- if(ret){
- DBG (5, "coarsecal: error sending d2 cmd\n");
- return ret;
- }
- if(stat[0] != 6){
- DBG (5, "coarsecal: cmd bad d2 status?\n");
- return SANE_STATUS_IO_ERROR;
- }
-
- s->cal_image.image = &s->coarsecal;
- update_transfer_totals(&s->cal_image);
-
- while(!s->cal_image.done){
- ret = read_from_scanner(s,&s->cal_image);
- if(ret){
- DBG (5, "coarsecal: cant read from scanner\n");
- return ret;
- }
- }
- /* convert the raw data into normal packed pixel data */
- descramble_raw(s, &s->cal_image);
-
/* gather statistics: count the proportion of 255-valued pixels in each color channel */
/* count the average pixel value in each color channel */
for (i = 0; i < s->coarsecal.pages; i++)
@@ -2645,7 +2856,7 @@ coarsecal(struct scanner *s)
/* apply the color correction factors to the averages */
for (i = 0; i < s->coarsecal.pages; i++)
for (j = 0; j < 3; j++)
- rgb_avg[i][j] *= white_factor[j];
+ rgb_avg[i][j] *= s->white_factor[j];
/* set the gain so that none of the color channels are clipping, ie take the highest channel values */
for (i = 0; i < s->coarsecal.pages; i++)
{
@@ -2662,9 +2873,9 @@ coarsecal(struct scanner *s)
}
zcount[i] = MAX3(rgb_hicount[i][0], rgb_hicount[i][1], rgb_hicount[i][2]);
}
- DBG(15, "coarsecal gain: average RGB values front: (%i,%i,%i) back: (%i,%i,%i)\n",
+ DBG(15, "coarsecal_light gain: average RGB values front: (%i,%i,%i) back: (%i,%i,%i)\n",
rgb_avg[0][0], rgb_avg[0][1], rgb_avg[0][2], rgb_avg[1][0], rgb_avg[1][1], rgb_avg[1][2]);
- DBG(15, "coarsecal gain: 255-valued pixel count front: (%g,%g,%g) back: (%g,%g,%g)\n",
+ DBG(15, "coarsecal_light gain: 255-valued pixel count front: (%g,%g,%g) back: (%g,%g,%g)\n",
rgb_hicount[0][0]/10.0f, rgb_hicount[0][1]/10.0f, rgb_hicount[0][2]/10.0f,
rgb_hicount[1][0]/10.0f, rgb_hicount[1][1]/10.0f, rgb_hicount[1][2]/10.0f);
@@ -2689,12 +2900,12 @@ coarsecal(struct scanner *s)
if (cal_good[0] + cal_good[1] == s->coarsecal.pages) break;
/* update the coarsecal payload to use the new gain parameters */
- if (s->model == MODEL_S300)
+ if (s->model == MODEL_S300 || s->model == MODEL_S1300i)
{
pay[11] = param[0];
pay[13] = param[1];
}
- else /* (s->model == MODEL_FI60F) */
+ else /* MODEL_S1100 or MODEL_FI60F or MODEL_FI65F */
{
pay[11] = param[0];
pay[13] = param[0];
@@ -2702,6 +2913,49 @@ coarsecal(struct scanner *s)
}
}
+ DBG (5, "coarsecal_light: finish\n");
+ return ret;
+}
+
+static SANE_Status
+coarsecal(struct scanner *s)
+{
+ SANE_Status ret = SANE_STATUS_GOOD;
+ unsigned char pay[28];
+ size_t payLen;
+
+ DBG (10, "coarsecal: start\n");
+
+ payLen = sizeof(pay);
+
+ if(s->model == MODEL_S300){
+ memcpy(pay,coarseCalData_S300,payLen);
+ }
+ else if(s->model == MODEL_S1300i){
+ memcpy(pay,coarseCalData_S1300i,payLen);
+ }
+ else if(s->model == MODEL_S1100){
+ memcpy(pay,coarseCalData_S1100,payLen);
+ }
+ else{
+ memcpy(pay,coarseCalData_FI60F,payLen);
+ }
+
+ /* ask for 1 line */
+ ret = set_window(s, WINDOW_COARSECAL);
+ if(ret){
+ DBG (5, "coarsecal: error sending setwindow\n");
+ return ret;
+ }
+
+ if(s->model == MODEL_S1100){
+ ret = coarsecal_send_cal(s, pay);
+ }
+ else{
+ ret = coarsecal_dark(s, pay);
+ ret = coarsecal_light(s, pay);
+ }
+
DBG (10, "coarsecal: finish\n");
return ret;
}
@@ -2718,18 +2972,63 @@ finecal_send_cal(struct scanner *s)
unsigned char stat[2];
int i, j, k;
- unsigned short *p_out, *p_in = (unsigned short *) s->sendcal.buffer;
- int planes = (s->model == MODEL_S300) ? 2 : 3;
+ unsigned char *p_out, *p_in = s->sendcal.buffer;
+ int planes;
+
+ if(s->model == MODEL_FI60F || s->model == MODEL_FI65F)
+ planes = 3;
+ if(s->model == MODEL_S300 || s->model == MODEL_S1300i)
+ planes = 2;
/* scramble the raster buffer data into scanner raw format */
+ /* this is reverse of descramble_raw */
memset(s->cal_data.raw_data, 0, s->cal_data.line_stride);
- for (i = 0; i < planes; i++)
+
+ if(s->model == MODEL_S1100){
+ planes = 1;
+
+ for (k = 0; k < s->sendcal.width_pix; k++){ /* column (x) */
+
+ /* input is RrGgBb (capital is offset, small is gain) */
+ /* output is Bb...BbRr...RrGg...Gg*/
+
+ /*red*/
+ p_out = s->cal_data.raw_data + s->cal_data.plane_stride + k*2;
+ *p_out = *p_in;
+ p_out++;
+ p_in++;
+ *p_out = *p_in;
+ p_in++;
+
+ /*green*/
+ p_out = s->cal_data.raw_data + 2*s->cal_data.plane_stride + k*2;
+ *p_out = *p_in;
+ p_out++;
+ p_in++;
+ *p_out = *p_in;
+ p_in++;
+
+ /*blue*/
+ p_out = s->cal_data.raw_data + k*2;
+ *p_out = *p_in;
+ p_out++;
+ p_in++;
+ *p_out = *p_in;
+ p_in++;
+ }
+ }
+
+ else{
+ for (i = 0; i < planes; i++)
for (j = 0; j < s->cal_data.plane_width; j++)
for (k = 0; k < 3; k++)
{
- p_out = (unsigned short *) (s->cal_data.raw_data + k * s->cal_data.plane_stride + j * 6 + i * 2);
- *p_out = *p_in++; /* dark offset, gain */
+ p_out = (s->cal_data.raw_data + k * s->cal_data.plane_stride + j * 6 + i * 2);
+ *p_out = *p_in++; /* dark offset */
+ p_out++;
+ *p_out = *p_in++; /* gain */
}
+ }
ret = set_window(s, WINDOW_SENDCAL);
if(ret){
@@ -2906,13 +3205,21 @@ finecal(struct scanner *s)
{
SANE_Status ret = SANE_STATUS_GOOD;
- const int max_pages = (s->model == MODEL_S300 ? 2 : 1);
+ int max_pages;
int gain_delta = 0xff - 0xbf;
float *gain_slope, *last_error;
int i, j, k, idx, try_count, cal_good;
DBG (10, "finecal: start\n");
+ if (s->model == MODEL_S300 || s->model == MODEL_S1300i) { /* S300, S1300 */
+ max_pages = 2;
+ }
+ else /* fi-60f, S1100 */
+ {
+ max_pages = 1;
+ }
+
/* set fine dark offset to 0 and fix all fine gains to lowest parameter (0xFF) */
for (i = 0; i < s->sendcal.width_bytes * s->sendcal.pages / 2; i++)
{
@@ -3008,7 +3315,7 @@ finecal(struct scanner *s)
for (k = 0; k < 3; k++)
{
int pixvalue = s->lightcal.buffer[idx];
- float pixerror = (fine_gain_target[i] * white_factor[k] - pixvalue);
+ float pixerror = (fine_gain_target[i] * s->white_factor[k] - pixvalue);
int oldgain = s->sendcal.buffer[idx * 2 + 1];
int newgain;
/* if we overshot the last correction, reduce the gain_slope */
@@ -3084,6 +3391,9 @@ finecal(struct scanner *s)
return ret;
}
+/*
+ * set scanner lamp brightness
+ */
static SANE_Status
lamp(struct scanner *s, unsigned char set)
{
@@ -3247,16 +3557,36 @@ send_lut (struct scanner *s)
size_t cmdLen = 2;
unsigned char stat[1];
size_t statLen = 1;
- unsigned char out[0x6000];
- size_t outLen = 0x6000;
+ unsigned char *out;
+ size_t outLen;
int i, j;
double b, slope, offset;
- int width = outLen / 6; /* 3 colors, 2 bytes */
- int height = width; /* square table */
+ int width;
+ int height;
DBG (10, "send_lut: start\n");
+ if (s->model == MODEL_S1100){
+ outLen = 0x200;
+ width = outLen / 2; /* 1 color, 2 bytes */
+ height = width; /* square table */
+ }
+ else if (s->model == MODEL_FI65F){
+ outLen = 0x600;
+ width = outLen / 6; /* 3 color, 2 bytes */
+ height = width; /* square table */
+ }
+ else {
+ outLen = 0x6000;
+ width = outLen / 6; /* 3 colors, 2 bytes */
+ height = width; /* square table */
+ }
+ out = ( unsigned char *)malloc(outLen*sizeof(unsigned char));
+ if (out == NULL){
+ return SANE_STATUS_NO_MEM;
+ }
+
/* contrast is converted to a slope [0,90] degrees:
* first [-127,127] to [0,254] then to [0,1]
* then multiply by PI/2 to convert to radians
@@ -3287,18 +3617,38 @@ send_lut (struct scanner *s)
if(j>(height-1)){
j=height-1;
}
-
- /*first table, le order*/
- out[i*2] = j & 0xff;
- out[i*2+1] = (j >> 8) & 0x0f;
-
- /*second table, le order*/
- out[width*2 + i*2] = j & 0xff;
- out[width*2 + i*2+1] = (j >> 8) & 0x0f;
- /*third table, le order*/
- out[width*4 + i*2] = j & 0xff;
- out[width*4 + i*2+1] = (j >> 8) & 0x0f;
+ if (s->model == MODEL_S1100){
+ /*only one table, be order*/
+ out[i*2] = (j >> 8) & 0xff;
+ out[i*2+1] = j & 0xff;
+ }
+ else if (s->model == MODEL_FI65F){
+ /*first table, be order*/
+ out[i*2] = (j >> 8) & 0xff;
+ out[i*2+1] = j & 0xff;
+
+ /*second table, be order*/
+ out[width*2 + i*2] = (j >> 8) & 0xff;
+ out[width*2 + i*2+1] = j & 0xff;
+
+ /*third table, be order*/
+ out[width*4 + i*2] = (j >> 8) & 0xff;
+ out[width*4 + i*2+1] = j & 0xff;
+ }
+ else {
+ /*first table, le order*/
+ out[i*2] = j & 0xff;
+ out[i*2+1] = (j >> 8) & 0x0f;
+
+ /*second table, le order*/
+ out[width*2 + i*2] = j & 0xff;
+ out[width*2 + i*2+1] = (j >> 8) & 0x0f;
+
+ /*third table, le order*/
+ out[width*4 + i*2] = j & 0xff;
+ out[width*4 + i*2+1] = (j >> 8) & 0x0f;
+ }
}
ret = do_cmd(
@@ -3386,11 +3736,10 @@ get_hardware_status (struct scanner *s)
}
static SANE_Status
-ingest(struct scanner *s)
+object_position(struct scanner *s, int ingest)
{
SANE_Status ret = SANE_STATUS_GOOD;
int i;
-
unsigned char cmd[2];
size_t cmdLen = sizeof(cmd);
unsigned char stat[1];
@@ -3398,10 +3747,11 @@ ingest(struct scanner *s)
unsigned char pay[2];
size_t payLen = sizeof(pay);
- DBG (10, "ingest: start\n");
+ DBG (10, "object_position: start\n");
- for(i=0;i<5;i++){
-
+ i = (ingest)?5:1;
+
+ while(i--){
/*send paper load cmd*/
cmd[0] = 0x1b;
cmd[1] = 0xd4;
@@ -3414,18 +3764,18 @@ ingest(struct scanner *s)
stat, &statLen
);
if(ret){
- DBG (5, "ingest: error sending cmd\n");
+ DBG (5, "object_position: error sending cmd\n");
return ret;
}
if(stat[0] != 6){
- DBG (5, "ingest: cmd bad status? %d\n",stat[0]);
+ DBG (5, "object_position: cmd bad status? %d\n",stat[0]);
continue;
}
/*send payload*/
statLen = 1;
payLen = 1;
- pay[0] = 1;
+ pay[0] = ingest;
ret = do_cmd(
s, 0,
@@ -3434,25 +3784,25 @@ ingest(struct scanner *s)
stat, &statLen
);
if(ret){
- DBG (5, "ingest: error sending payload\n");
+ DBG (5, "object_position: error sending payload\n");
return ret;
}
if(stat[0] == 6){
- DBG (5, "ingest: found paper?\n");
+ DBG (5, "object_position: found paper?\n");
break;
}
else if(stat[0] == 0x15 || stat[0] == 0){
- DBG (5, "ingest: no paper?\n");
+ DBG (5, "object_position: no paper?\n");
ret=SANE_STATUS_NO_DOCS;
continue;
}
else{
- DBG (5, "ingest: payload bad status?\n");
+ DBG (5, "object_position: payload bad status?\n");
return SANE_STATUS_IO_ERROR;
}
}
- DBG (10, "ingest: finish\n");
+ DBG (10, "object_position: finish\n");
return ret;
}
@@ -3467,7 +3817,7 @@ scan(struct scanner *s)
DBG (10, "scan: start\n");
- if(s->model == MODEL_S300){
+ if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i){
cmd[1] = 0xd6;
}
@@ -3525,9 +3875,29 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
page = &s->pages[s->side];
/* have sent all of current buffer */
- if(page->done){
+ if(s->fullscan.done && page->done){
DBG (10, "sane_read: returning eof\n");
- return SANE_STATUS_EOF;
+
+ /*S1100 needs help to turn off button*/
+ if(s->model == MODEL_S1100){
+ usleep(15000);
+
+ /* eject paper */
+ ret = object_position(s,EPJITSU_PAPER_EJECT);
+ if (ret != SANE_STATUS_GOOD && ret != SANE_STATUS_NO_DOCS) {
+ DBG (5, "sane_read: ERROR: failed to eject\n");
+ return ret;
+ }
+
+ /* reset flashing button? */
+ ret = six5(s);
+ if (ret != SANE_STATUS_GOOD) {
+ DBG (5, "sane_read: ERROR: failed to six5\n");
+ return ret;
+ }
+ }
+
+ return SANE_STATUS_EOF;
}
/* scan not finished, get more into block buffer */
@@ -3543,8 +3913,8 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
DBG (15, "sane_read: shrinking block to %lu\n", (unsigned long)remainTotal);
s->block_xfr.total_bytes = remainTotal;
}
- /* send d3 cmd for S300 */
- if(s->model == MODEL_S300)
+ /* send d3 cmd for S300, S1100, S1300 */
+ if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i)
{
unsigned char cmd[] = {0x1b, 0xd3};
size_t cmdLen = 2;
@@ -3586,8 +3956,8 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
s->block_xfr.done = 0;
- /* get the 0x43 cmd for the S300 */
- if(s->model == MODEL_S300){
+ /* get the 0x43 cmd for the S300, S1100, S1300 */
+ if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i){
unsigned char cmd[] = {0x1b, 0x43};
size_t cmdLen = 2;
@@ -3672,7 +4042,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
page->bytes_read += *len;
/* sent it all, return eof on next read */
- if(s->fullscan.done && page->bytes_read == page->bytes_scanned){
+ if(page->bytes_read == page->bytes_scanned && s->fullscan.done){
DBG (10, "sane_read: side done\n");
page->done = 1;
}
@@ -3683,36 +4053,180 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len
return ret;
}
+static SANE_Status
+six5 (struct scanner *s)
+{
+ SANE_Status ret = SANE_STATUS_GOOD;
+
+ unsigned char cmd[2];
+ size_t cmdLen = sizeof(cmd);
+ unsigned char stat[1];
+ size_t statLen = sizeof(stat);
+
+ DBG (10, "six5: start\n");
+
+ cmd[0] = 0x1b;
+ cmd[1] = 0x65;
+ statLen = 1;
+
+ ret = do_cmd(
+ s, 0,
+ cmd, cmdLen,
+ NULL, 0,
+ stat, &statLen
+ );
+ if(ret){
+ DBG (5, "six5: error sending cmd\n");
+ return ret;
+ }
+ if(stat[0] != 6){
+ DBG (5, "six5: cmd bad status? %d\n",stat[0]);
+ return SANE_STATUS_IO_ERROR;
+ }
+
+ DBG (10, "six5: finish\n");
+
+ return ret;
+}
+
/* de-scrambles the raw data from the scanner into the image buffer */
+/* the output image might be lower dpi than input image, so we scale horizontally */
static SANE_Status
descramble_raw(struct scanner *s, struct transfer * tp)
{
SANE_Status ret = SANE_STATUS_GOOD;
- unsigned char *p_in, *p_out = tp->image->buffer;
+ unsigned char *p_out = tp->image->buffer;
int height = tp->total_bytes / tp->line_stride;
- int i, j, k, l;
+ int i, j, k;
- if (s->model == MODEL_S300)
- {
- for (i = 0; i < 2; i++) /* page, front/back */
- for (j = 0; j < height; j++) /* row (y)*/
- for (k = 0; k < tp->plane_width; k++) /* column (x) */
- for (l = 0; l < 3; l++) /* color component */
- {
- p_in = (unsigned char *) tp->raw_data + (j * tp->line_stride) + (l * tp->plane_stride) + k * 3 + i;
- *p_out++ = *p_in;
- }
+ if (s->model == MODEL_S300 || s->model == MODEL_S1300i) {
+ for (i = 0; i < 2; i++){ /* page, front/back */
+ for (j = 0; j < height; j++){ /* row (y)*/
+ int curr_col = 0;
+ int r=0, g=0, b=0, ppc=0;
+
+ for (k = 0; k <= tp->plane_width; k++){ /* column (x) */
+ int this_col = k*tp->image->x_res/tp->x_res;
+
+ /* going to change output pixel, dump rgb and reset */
+ if(ppc && curr_col != this_col){
+ *p_out = r/ppc;
+ p_out++;
+
+ *p_out = g/ppc;
+ p_out++;
+
+ *p_out = b/ppc;
+ p_out++;
+
+ r = g = b = ppc = 0;
+
+ curr_col = this_col;
+ }
+
+ if(k == tp->plane_width || this_col >= tp->image->width_pix){
+ break;
+ }
+
+ /*red is first*/
+ r += tp->raw_data[j*tp->line_stride + k*3 + i];
+
+ /*green is second*/
+ g += tp->raw_data[j*tp->line_stride + tp->plane_stride + k*3 + i];
+
+ /*blue is third*/
+ b += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k*3 + i];
+
+ ppc++;
+ }
+ }
+ }
}
- else /* MODEL_FI60F */
- {
- for (i = 0; i < height; i++) /* row (y)*/
- for (j = 0; j < 3; j++) /* read head */
- for (k = 0; k < tp->plane_width; k++) /* column within the read head */
- for (l = 0; l < 3; l++) /* color component */
- {
- p_in = (unsigned char *) tp->raw_data + (i * tp->line_stride) + (l * tp->plane_stride) + k * 3 + j;
- *p_out++ = *p_in;
- }
+ else if (s->model == MODEL_S1100){
+ for (j = 0; j < height; j++){ /* row (y)*/
+ int curr_col = 0;
+ int r=0, g=0, b=0, ppc=0;
+
+ for (k = 0; k <= tp->plane_width; k++){ /* column (x) */
+ int this_col = k*tp->image->x_res/tp->x_res;
+
+ /* going to change output pixel, dump rgb and reset */
+ if(ppc && curr_col != this_col){
+ *p_out = r/ppc;
+ p_out++;
+
+ *p_out = g/ppc;
+ p_out++;
+
+ *p_out = b/ppc;
+ p_out++;
+
+ r = g = b = ppc = 0;
+
+ curr_col = this_col;
+ }
+
+ if(k == tp->plane_width || this_col >= tp->image->width_pix){
+ break;
+ }
+
+ /*red is second*/
+ r += tp->raw_data[j*tp->line_stride + tp->plane_stride + k];
+
+ /*green is third*/
+ g += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k];
+
+ /*blue is first*/
+ b += tp->raw_data[j*tp->line_stride + k];
+
+ ppc++;
+ }
+ }
+ }
+ else { /* MODEL_FI60F or MODEL_FI65F */
+
+ for (j = 0; j < height; j++){ /* row (y)*/
+ int curr_col = 0;
+
+ for (i = 0; i < 3; i++){ /* read head */
+ int r=0, g=0, b=0, ppc=0;
+
+ for (k = 0; k <= tp->plane_width; k++){ /* column (x) within the read head */
+ int this_col = (k+i*tp->plane_width)*tp->image->x_res/tp->x_res;
+
+ /* going to change output pixel, dump rgb and reset */
+ if(ppc && curr_col != this_col){
+ *p_out = r/ppc;
+ p_out++;
+
+ *p_out = g/ppc;
+ p_out++;
+
+ *p_out = b/ppc;
+ p_out++;
+
+ r = g = b = ppc = 0;
+
+ curr_col = this_col;
+ }
+
+ if(k == tp->plane_width || this_col >= tp->image->width_pix){
+ break;
+ }
+
+ /*red is first*/
+ r += tp->raw_data[j*tp->line_stride + k*3 + i];
+
+ /*green is second*/
+ g += tp->raw_data[j*tp->line_stride + tp->plane_stride + k*3 + i];
+
+ /*blue is third*/
+ b += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k*3 + i];
+
+ ppc++;
+ }
+ }
+ }
}
return ret;
@@ -3725,9 +4239,11 @@ read_from_scanner(struct scanner *s, struct transfer * tp)
SANE_Status ret=SANE_STATUS_GOOD;
size_t bytes = MAX_IMG_PASS;
size_t remainBlock = tp->total_bytes - tp->rx_bytes + 8;
-
- /* determine amount to ask for */
- if(bytes > remainBlock){
+ unsigned char * buf;
+ size_t bufLen;
+
+ /* determine amount to ask for, S1300i wants big requests */
+ if(bytes > remainBlock && s->model != MODEL_S1300i){
bytes = remainBlock;
}
@@ -3745,70 +4261,141 @@ read_from_scanner(struct scanner *s, struct transfer * tp)
return SANE_STATUS_INVAL;
}
+ bufLen = bytes;
+ buf = malloc(bufLen);
+ if(!buf){
+ DBG (5, "read_from_scanner: failed to alloc mem\n");
+ return SANE_STATUS_NO_MEM;
+ }
+
ret = do_cmd(
s, 0,
NULL, 0,
NULL, 0,
- tp->raw_data + tp->rx_bytes, &bytes
+ buf, &bytes
);
-
+
/* full read or short read */
if (ret == SANE_STATUS_GOOD || (ret == SANE_STATUS_EOF && bytes) ) {
DBG(15,"read_from_scanner: got GOOD/EOF (%lu)\n",(unsigned long)bytes);
+ if(bytes > remainBlock){
+ DBG(15,"read_from_scanner: block too big?\n");
+ bytes = remainBlock;
+ }
+
if(bytes == remainBlock){
DBG(15,"read_from_scanner: block done, ignoring trailer\n");
bytes -= 8;
tp->done = 1;
}
- ret = SANE_STATUS_GOOD;
+ memcpy(tp->raw_data + tp->rx_bytes, buf, bytes);
tp->rx_bytes += bytes;
+
+ ret = SANE_STATUS_GOOD;
}
else {
DBG(5, "read_from_scanner: error reading status = %d\n", ret);
}
-
+
+ free(buf);
+
DBG (10, "read_from_scanner: finish rB:%lu len:%lu\n",
- (unsigned long)(tp->total_bytes - tp->rx_bytes), (unsigned long)bytes);
+ (unsigned long)(tp->total_bytes - tp->rx_bytes + 8), (unsigned long)bytes);
return ret;
}
/* copies block buffer into front or back image buffer */
/* converts pixel data from RGB Color to the output format */
+/* the output image might be lower dpi than input image, so we scale vertically */
static SANE_Status
copy_block_to_page(struct scanner *s,int side)
{
SANE_Status ret = SANE_STATUS_GOOD;
struct transfer * block = &s->block_xfr;
struct page * page = &s->pages[side];
- int height = block->total_bytes / block->line_stride;
- int width = block->image->width_pix;
+ int image_height = block->total_bytes / block->line_stride;
+ int page_height = SCANNER_UNIT_TO_PIX(s->page_height, s->resolution);
+ int page_width = page->image->width_pix;
int block_page_stride = block->image->width_bytes * block->image->height;
- int page_y_offset = page->bytes_scanned / page->image->width_bytes;
- int line_reverse = (side == SIDE_BACK) || (s->model == MODEL_FI60F);
- int i,j;
+ int line_reverse = (side == SIDE_BACK) || (s->model == MODEL_FI60F) || (s->model == MODEL_FI65F);
+ int i,j,k=0,l=0;
+
+ int curr_in_row = s->fullscan.rx_bytes/s->fullscan.width_bytes;
+ int last_out_row = (page->bytes_scanned / page->image->width_bytes) - 1;
DBG (10, "copy_block_to_page: start\n");
+ /* skip padding and tl_y */
+ if (s->fullscan.rx_bytes + s->block_xfr.rx_bytes < block->line_stride * page->image->y_skip_offset)
+ {
+ DBG (10, "copy_block_to_page: before the start? %d\n", side);
+ return ret;
+ }
+ else if (s->fullscan.rx_bytes < block->line_stride * page->image->y_skip_offset)
+ {
+ k = page->image->y_skip_offset - s->fullscan.rx_bytes / block->line_stride;
+ DBG (10, "copy_block_to_page: k start? %d\n", k);
+ }
+
+ /* skip trailer */
+ if (s->page_height)
+ {
+ DBG (10, "copy_block_to_page: ph %d\n", s->page_height);
+ if (s->fullscan.rx_bytes > block->line_stride * page->image->y_skip_offset + page_height * block->line_stride)
+ {
+ DBG (10, "copy_block_to_page: off the end? %d\n", side);
+ return ret;
+ }
+ else if (s->fullscan.rx_bytes + s->block_xfr.rx_bytes
+ > block->line_stride * page->image->y_skip_offset + page_height * block->line_stride)
+ {
+ l = (s->fullscan.rx_bytes + s->block_xfr.rx_bytes) / block->line_stride
+ - page_height - page->image->y_skip_offset;
+ }
+ }
+
/* loop over all the lines in the block */
- for (i = 0; i < height; i++)
+ for (i = k; i < image_height-l; i++)
{
- unsigned char * p_in = block->image->buffer + (side * block_page_stride) + (i * block->image->width_bytes);
- unsigned char * p_out = page->image->buffer + ((i + page_y_offset) * page->image->width_bytes);
+ /* determine source and dest rows (dpi scaling) */
+ int this_in_row = curr_in_row + i;
+ int this_out_row = (this_in_row - page->image->y_skip_offset) * page->image->y_res / s->fullscan.y_res;
+ DBG (15, "copy_block_to_page: in %d out %d lastout %d\n", this_in_row, this_out_row, last_out_row);
+ DBG (15, "copy_block_to_page: bs %d wb %d\n", page->bytes_scanned, page->image->width_bytes);
+
+ /* don't walk off the end of the output buffer */
+ if(this_out_row >= page->image->height || this_out_row < 0){
+ DBG (10, "copy_block_to_page: out of space? %d\n", side);
+ DBG (10, "copy_block_to_page: rx:%d tx:%d tot:%d line:%d\n",
+ page->bytes_scanned, page->bytes_read, page->bytes_total,page->image->width_bytes);
+ return ret;
+ }
+
+ /* ok, different output row, so we do the math */
+ if(this_out_row > last_out_row){
+
+ unsigned char * p_in = block->image->buffer + (side * block_page_stride)
+ + (i * block->image->width_bytes) + page->image->x_start_offset * 3;
+ unsigned char * p_out = page->image->buffer + this_out_row * page->image->width_bytes;
unsigned char * lineStart = p_out;
+
+ last_out_row = this_out_row;
+
/* reverse order for back side or FI-60F scanner */
if (line_reverse)
- p_in += (width - 1) * 3;
+ p_in += (page_width - 1) * 3;
+
/* convert all of the pixels in this row */
- for (j = 0; j < width; j++)
+ for (j = 0; j < page_width; j++)
{
unsigned char r, g, b;
- if (s->model == MODEL_S300)
+ if (s->model == MODEL_S300 || s->model == MODEL_S1300i)
{ r = p_in[1]; g = p_in[2]; b = p_in[0]; }
- else /* (s->model == MODEL_FI60F) */
+ else /* MODEL_FI60F or MODEL_FI65F or MODEL_S1100 */
{ r = p_in[0]; g = p_in[1]; b = p_in[2]; }
if (s->mode == MODE_COLOR)
{
@@ -3822,28 +4409,28 @@ copy_block_to_page(struct scanner *s,int side)
}
else if (s->mode == MODE_LINEART)
{
- s->dt.buffer[j] = (r + g + b) / 3;
+ s->dt.buffer[j] = (r + g + b) / 3; /* stores dt temp image buffer and binarize afterword */
}
if (line_reverse)
p_in -= 3;
else
p_in += 3;
}
- /* for MODE_LINEART, binarize the gray line stored in the temp image buffer */
+
+ /* skip non-transfer pixels in block image buffer */
+ if (line_reverse)
+ p_in -= page->image->x_offset_bytes;
+ else
+ p_in += page->image->x_offset_bytes;
+
+ /* for MODE_LINEART, binarize the gray line stored in the temp image buffer(dt) */
+ /* bacause dt.width = page_width, we pass page_width */
if (s->mode == MODE_LINEART)
- binarize_line(s, lineStart, width);
- /*add a periodic row because of non-square pixels*/
- /*FIXME: only works with 225x200*/
- if (s->resolution_x > s->resolution_y && (i + page_y_offset) % 9 == 8)
- {
- memcpy(lineStart + page->image->width_bytes, lineStart, page->image->width_bytes);
- page_y_offset += 1;
- page->bytes_scanned += page->image->width_bytes;
- }
- }
+ binarize_line(s, lineStart, page_width);
- /* update the page counter of bytes scanned */
- page->bytes_scanned += page->image->width_bytes * height;
+ page->bytes_scanned += page->image->width_bytes;
+ }
+ }
DBG (10, "copy_block_to_page: finish\n");
@@ -3858,7 +4445,7 @@ binarize_line(struct scanner *s, unsigned char *lineOut, int width)
int j, windowX, sum = 0;
/* ~1mm works best, but the window needs to have odd # of pixels */
- windowX = 6 * s->resolution_x / 150;
+ windowX = 6 * s->resolution / 150;
if (!(windowX % 2)) windowX++;
/*second, prefill the sliding sum*/