diff options
Diffstat (limited to 'backend/epjitsu.c')
-rw-r--r-- | backend/epjitsu.c | 324 |
1 files changed, 212 insertions, 112 deletions
diff --git a/backend/epjitsu.c b/backend/epjitsu.c index 7d987dc..ce79a20 100644 --- a/backend/epjitsu.c +++ b/backend/epjitsu.c @@ -1,6 +1,14 @@ /* sane - Scanner Access Now Easy. - This file is part of the SANE package. + This file implements a SANE backend for the Fujitsu fi-60F, the + ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. + + Copyright 2007-2015 by m. allan noah <kitno455 at gmail dot com> + Copyright 2009 by Richard Goedeken <richard at fascinationsoftware dot com> + + Development funded by Microdea, Inc., TrueCheck, Inc. and Archivista, GmbH + + -------------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -40,16 +48,6 @@ -------------------------------------------------------------------------- - This file implements a SANE backend for the Fujitsu fi-60F, the - ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. - - Copyright 2007-2010 by m. allan noah <kitno455 at gmail dot com> - Copyright 2009 by Richard Goedeken <richard at fascinationsoftware dot com> - - Development funded by Microdea, Inc., TrueCheck, Inc. and Archivista, GmbH - - -------------------------------------------------------------------------- - The source code is divided in sections which you can easily find by searching for the tag "@@". @@ -151,6 +149,14 @@ - call change_params after changing page_width v28 2015-03-23, MAN - call get_hardware_status before starting scan + v29 2017-03-18, MAN + - fix infinite loop when scaling in Y direction + v30 2017-03-21, MAN + - fix image truncation when using 150 DPI in Y direction + - add 200 and 400 DPI Y direction support for fi-60F/65F + v31 2017-04-09, MAN + - hardware gray support for fi-60F/65F (disabled pending calibration) + - merge fi-60F/65F settings SANE FLOW DIAGRAM @@ -199,7 +205,7 @@ #include "epjitsu-cmd.h" #define DEBUG 1 -#define BUILD 28 +#define BUILD 31 #ifndef MAX3 #define MAX3(a,b,c) ((a) > (b) ? ((a) > (c) ? a : c) : ((b) > (c) ? b : c)) @@ -1770,6 +1776,7 @@ update_transfer_totals(struct transfer * t) /* we hard-code the list (determined from usb snoops) here */ struct model_res { int model; + int mode; int x_res; int y_res; int usb_power; @@ -1802,141 +1809,153 @@ struct model_res { static struct model_res settings[] = { /*S300 AC*/ -/* 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, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S300, MODE_COLOR, 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*3, 2100*3, 1944, 28, 8192*3, 2800*3, 2592, + { MODEL_S300, MODE_COLOR, 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*3, 2800*3, 2592, 21, 8192*3, 2800*3, 2592, + { MODEL_S300, MODE_COLOR, 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*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, + { MODEL_S300, MODE_COLOR, 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 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, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S300, MODE_COLOR, 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*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, + { MODEL_S300, MODE_COLOR, 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*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, + { MODEL_S300, MODE_COLOR, 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*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, + { MODEL_S300, MODE_COLOR, 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, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S1300i, MODE_COLOR, 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, + { MODEL_S1300i, MODE_COLOR, 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, + { MODEL_S1300i, MODE_COLOR, 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, + { MODEL_S1300i, MODE_COLOR, 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, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S1300i, MODE_COLOR, 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, + { MODEL_S1300i, MODE_COLOR, 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, + { MODEL_S1300i, MODE_COLOR, 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, + { MODEL_S1300i, MODE_COLOR, 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 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, + /*fi-60F/65F GRAY */ +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ +/* disabled until calibration code supports grayscale + { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 300, 300, 0, 1296, 32, 1749, 32, 1440, 480, 432, 364, 2400*3, 958*3, 432, setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, - sendCal2Header_FI60F_300, setWindowScan_FI60F_300 }, + sendCal2Header_FI60F_300, setWindowScan_FI60F_300_g }, - { MODEL_FI60F, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, + { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 600, 400, 0, 2592, 32, 2332, 32, 2592, 864, 864, 202, 2848*3, 978*3, 864, setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, - sendCal2Header_FI60F_600, setWindowScan_FI60F_600 }, + sendCal2Header_FI60F_600, setWindowScan_FI60F_400_g }, - /*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 | MODEL_FI65F, MODE_GRAYSCALE, 600, 600, 0, 2592, 32, 3498, 32, 2592, 864, 864, 202, 2848*3, 978*3, 864, + setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, + setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, + sendCal2Header_FI60F_600, setWindowScan_FI60F_600_g }, +*/ + + /*fi-60F/65F*/ +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 150, 0, 1296, 32, 875, 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_150 }, - { MODEL_FI65F, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 200, 0, 1296, 32, 1166, 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_200 }, + + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 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_FI65F, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 600, 400, 0, 2592, 32, 2332, 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_400 }, + + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 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 }, /*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, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S1100, MODE_COLOR, 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, + { MODEL_S1100, MODE_COLOR, 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, + { MODEL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }, }; @@ -1955,7 +1974,8 @@ change_params(struct scanner *s) DBG (10, "change_params: start\n"); do { - if(settings[i].model == s->model + if(settings[i].model & s->model + && settings[i].mode <= s->mode && settings[i].x_res >= s->resolution && settings[i].y_res >= s->resolution && settings[i].usb_power == s->usb_power @@ -2038,11 +2058,12 @@ change_params(struct scanner *s) s->br_x = (s->max_x + s->page_width)/2; /*=============================================================*/ - /* set up the calibration structs */ + /* set up the calibration scan 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.mode = MODE_COLOR; s->cal_image.x_res = settings[i].x_res; s->cal_image.y_res = settings[i].y_res; s->cal_image.raw_data = NULL; @@ -2052,38 +2073,19 @@ change_params(struct scanner *s) 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.mode = MODE_COLOR; 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; /*=============================================================*/ - /* 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 */ - /* 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; - /* set up the calibration image blocks */ width = s->cal_image.plane_width * img_heads; 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.mode = MODE_COLOR; 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; @@ -2095,13 +2097,18 @@ 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.mode = MODE_COLOR; 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; + /* this is bookkeeping for what we actually pull from the scanner */ + /* note that this has no image, just dimensions and counters */ + s->fullscan.width_bytes = settings[i].line_stride; + s->fullscan.mode = settings[i].mode; s->fullscan.x_res = settings[i].x_res; s->fullscan.y_res = settings[i].y_res; if(s->source == SOURCE_FLATBED || !s->page_height) @@ -2116,8 +2123,34 @@ change_params(struct scanner *s) } /*=============================================================*/ + /* set up the input block raw struct */ + /* this holds up to 512k of raw scan data */ + 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.mode = settings[i].mode; + 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 input block image struct */ + /* note that this is the same width/x_res as the final output image */ + /* but the mode, height and y_res are the same as block_xfr */ + width = (settings[i].max_x * s->resolution / settings[i].x_res); + s->block_img.width_pix = width; + s->block_img.width_bytes = width * (settings[i].mode == MODE_COLOR ? 3 : 1); + s->block_img.height = settings[i].block_height; + s->block_img.mode = settings[i].mode; + 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; + + /*=============================================================*/ /* set up the output image structs */ /* output image might be different from scan due to interpolation */ + s->front.mode = s->mode; s->front.x_res = s->resolution; s->front.y_res = s->resolution; if(s->source == SOURCE_FLATBED) @@ -2170,6 +2203,7 @@ change_params(struct scanner *s) /* 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.mode = s->front.mode; s->back.x_res = s->front.x_res; s->back.y_res = s->front.y_res; s->back.height = s->front.height; @@ -2182,6 +2216,7 @@ change_params(struct scanner *s) /* dynamic threshold temp buffer, in gray */ s->dt.width_pix = s->front.width_pix; s->dt.width_bytes = s->front.width_pix; + s->dt.mode = MODE_GRAYSCALE; s->dt.x_res = s->front.x_res; s->dt.y_res = s->front.y_res; s->dt.height = 1; @@ -3955,7 +3990,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len { DBG (15, "sane_read: block buffer full\n"); - /* convert the raw data into normal packed pixel data */ + /* convert the raw color data into normal packed pixel data */ descramble_raw(s, &s->block_xfr); s->block_xfr.done = 0; @@ -4095,6 +4130,8 @@ six5 (struct scanner *s) /* 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 */ +/* if the input image is mirrored left to right, we do not correct it here */ +/* if the input image has padding (at the end or between heads), it is removed here */ static SANE_Status descramble_raw(struct scanner *s, struct transfer * tp) { @@ -4103,6 +4140,13 @@ descramble_raw(struct scanner *s, struct transfer * tp) int height = tp->total_bytes / tp->line_stride; int i, j, k; + /* raw gray data handled in another function */ + if(tp->mode == MODE_GRAYSCALE){ + return descramble_raw_gray(s, tp); + } + + DBG(15, "descramble_raw: start\n"); + 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)*/ @@ -4233,6 +4277,47 @@ descramble_raw(struct scanner *s, struct transfer * tp) } } + DBG(15, "descramble_raw: finish %d\n", ret); + + return ret; +} + +/* de-scrambles the raw gray data from the scanner into the image buffer */ +/* the output image might be lower dpi than input image, so we scale horizontally */ +/* if the input image is mirrored left to right, we do not correct it here */ +/* if the input image has padding (at the end or between heads), it is removed here */ +static SANE_Status +descramble_raw_gray(struct scanner *s, struct transfer * tp) +{ + SANE_Status ret = SANE_STATUS_GOOD; + int height = tp->total_bytes / tp->line_stride; + int row, col_out; + + DBG(15, "descramble_raw_gray: start\n"); + + if (s->model == MODEL_FI60F || s->model == MODEL_FI65F) { + for (row = 0; row < height; row++){ + + unsigned char *p_in = tp->raw_data + row * tp->line_stride; + unsigned char *p_out = tp->image->buffer + row * tp->image->width_pix; + + for (col_out = 0; col_out < tp->image->width_pix; col_out++){ + int col_in = col_out * tp->x_res/tp->image->x_res; + int offset = col_in%tp->plane_width; + int step = col_in/tp->plane_width; + + *p_out = *(p_in + offset*3 + step); + p_out++; + } + } + } + + else{ + DBG(5, "internal error: descramble_raw_gray not supported\n"); + ret = SANE_STATUS_INVAL; + } + + DBG(15, "descramble_raw_gray: finish %d\n", ret); return ret; } @@ -4313,8 +4398,10 @@ read_from_scanner(struct scanner *s, struct transfer * tp) } /* copies block buffer into front or back image buffer */ -/* converts pixel data from RGB Color to the output format */ +/* converts pixel data from input mode (color/gray) to output mode (color/gray/binary) */ /* the output image might be lower dpi than input image, so we scale vertically */ +/* the input is already scaled horizontally and padding skipped if required */ +/* if the input is mirrored left to right, we fix it here */ static SANE_Status copy_block_to_page(struct scanner *s,int side) { @@ -4322,11 +4409,10 @@ copy_block_to_page(struct scanner *s,int side) struct transfer * block = &s->block_xfr; struct page * page = &s->pages[side]; 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 line_reverse = (side == SIDE_BACK) || (s->model == MODEL_FI60F) || (s->model == MODEL_FI65F); - int i,j,k=0,l=0; + int i,j,k=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; @@ -4334,7 +4420,7 @@ copy_block_to_page(struct scanner *s,int side) 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) + 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; @@ -4345,25 +4431,8 @@ copy_block_to_page(struct scanner *s,int side) 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 = k; i < image_height-l; i++) + for (i = k; i < image_height; i++) { /* determine source and dest rows (dpi scaling) */ int this_in_row = curr_in_row + i; @@ -4389,13 +4458,15 @@ copy_block_to_page(struct scanner *s,int side) last_out_row = this_out_row; - /* reverse order for back side or FI-60F scanner */ - if (line_reverse) + if (block->mode == MODE_COLOR){ + + /* reverse order for back side or FI-60F scanner */ + if (line_reverse) p_in += (page_width - 1) * 3; - - /* convert all of the pixels in this row */ - for (j = 0; j < page_width; j++) - { + + /* convert all of the pixels in this row */ + for (j = 0; j < page_width; j++) + { unsigned char r, g, b; if (s->model == MODEL_S300 || s->model == MODEL_S1300i) { r = p_in[1]; g = p_in[2]; b = p_in[0]; } @@ -4413,12 +4484,41 @@ copy_block_to_page(struct scanner *s,int side) } else if (s->mode == MODE_LINEART) { - s->dt.buffer[j] = (r + g + b) / 3; /* stores dt temp image buffer and binarize afterword */ + s->dt.buffer[j] = (r + g + b) / 3; /* stores dt temp image buffer and binarize afterward */ } if (line_reverse) p_in -= 3; else p_in += 3; + } + } + + /* grayscale input */ + else{ + unsigned char * p_in = block->image->buffer + (side * block_page_stride) + + (i * block->image->width_bytes) + page->image->x_start_offset; + + /* reverse order for back side or FI-60F scanner */ + if (line_reverse) + p_in += (page_width - 1); + + //memcpy(p_out,p_in,page->image->width_bytes); + + for (j = 0; j < page_width; j++) + { + if (s->mode == MODE_GRAYSCALE) + { + *p_out++ = *p_in; + } + else if (s->mode == MODE_LINEART) + { + s->dt.buffer[j] = *p_in; /* stores dt temp image buffer and binarize afterward */ + } + if (line_reverse) + p_in--; + else + p_in++; + } } /* skip non-transfer pixels in block image buffer */ @@ -4576,13 +4676,13 @@ destroy(struct scanner *s) teardown_buffers(s); if(s->sane.name){ - free(s->sane.name); + free((void *) s->sane.name); } if(s->sane.vendor){ - free(s->sane.vendor); + free((void *) s->sane.vendor); } if(s->sane.model){ - free(s->sane.model); + free((void *) s->sane.model); } free(s); |