From ef37bde7da7df7ccb49260640459becb3d220ba8 Mon Sep 17 00:00:00 2001 From: Nils Philippsen Date: Fri, 1 Feb 2013 16:54:06 +0100 Subject: [PATCH] coolscan2/3: support multi-scan option of some devices --- sane-backends-1.0.23-coolscan-multiscan.patch | 491 ++++++++++++++++++ sane-backends.spec | 4 + 2 files changed, 495 insertions(+) create mode 100644 sane-backends-1.0.23-coolscan-multiscan.patch diff --git a/sane-backends-1.0.23-coolscan-multiscan.patch b/sane-backends-1.0.23-coolscan-multiscan.patch new file mode 100644 index 0000000..ef62743 --- /dev/null +++ b/sane-backends-1.0.23-coolscan-multiscan.patch @@ -0,0 +1,491 @@ +From 9282aef3c04c50d198e54225dc1db26d5cf70d4d Mon Sep 17 00:00:00 2001 +From: Nils Philippsen +Date: Fri, 1 Feb 2013 16:50:29 +0100 +Subject: [PATCH] patch: coolscan-multiscan + +Squashed commit of the following: + +commit 8c83fd9274e41cc44e84c62eb4294e07e6651584 +Author: Nils Philippsen +Date: Fri Dec 14 19:00:42 2012 +0100 + + coolscan3: average multiple samples + + (ported from coolscan2, commit 4126b6796dfc79152408e387e923a73e96814191) + (cherry picked from commit a1273d1c6500ff9c8bf68946dda910da02834b01) + +commit 9856fd6b83eef5d5dde48b8627716bca48dde36f +Author: Nils Philippsen +Date: Fri Dec 14 18:20:08 2012 +0100 + + coolscan3: set multi-sampling on scanner + + (ported from coolscan2, commit 238565790449b5257c34ef4cb69edd789e884b7d) + (cherry picked from commit 2bc59796cad213d9a40b2eb0d4ecbf80e4e9b351) + +commit 946511ce3508c96cd749021a249d28b3b79e7daa +Author: Nils Philippsen +Date: Fri Dec 14 18:12:01 2012 +0100 + + coolscan3: only offer samples-per-scan for devices supporting it + + (ported from coolscan2, commit ed9ac6f15df070767f1532b24aad4b5b8e92156f) + (cherry picked from commit 6589dbd5c027fb008383ff5d748c1b9ec209d2b1) + +commit a75d020371e81e179b87050ed014fa36bac03d9a +Author: Nils Philippsen +Date: Fri Dec 14 18:09:28 2012 +0100 + + coolscan3: add samples-per-scan option + + (ported from coolscan2, commit 121afa695b94af64821a75adee919637ef5a1b73) + (cherry picked from commit 82139b08239f87d329c4f216655926bd7d9d6581) + +commit b9bf83802012646c9d40e1dab9843025fba0cc21 +Author: Nils Philippsen +Date: Sun Apr 1 05:01:09 2012 +0200 + + coolscan2: average multiple samples + (cherry picked from commit 4126b6796dfc79152408e387e923a73e96814191) + +commit bc12adabf430cae57bf195ef228b64e3d493b265 +Author: Nils Philippsen +Date: Sat Mar 31 20:48:37 2012 +0200 + + coolscan2: set multi-sampling on scanner + (cherry picked from commit 238565790449b5257c34ef4cb69edd789e884b7d) + +commit 924fd319a339fa48e2efe40ba2b8292336c33e7c +Author: Nils Philippsen +Date: Sat Mar 31 21:39:01 2012 +0200 + + coolscan2: only offer samples-per-scan for devices supporting it + (cherry picked from commit ed9ac6f15df070767f1532b24aad4b5b8e92156f) + +commit bdcb3aec8501d25560253a937ef1e5ddc06432cb +Author: Nils Philippsen +Date: Sat Mar 31 20:48:16 2012 +0200 + + coolscan2: add samples-per-scan option + (cherry picked from commit 121afa695b94af64821a75adee919637ef5a1b73) +--- + backend/coolscan2.c | 103 +++++++++++++++++++++++++++++++++++++++++++------- + backend/coolscan3.c | 106 ++++++++++++++++++++++++++++++++++++++++++++-------- + 2 files changed, 179 insertions(+), 30 deletions(-) + +diff --git a/backend/coolscan2.c b/backend/coolscan2.c +index 43d6c55..9f9efde 100644 +--- a/backend/coolscan2.c ++++ b/backend/coolscan2.c +@@ -181,6 +181,8 @@ typedef enum + + CS2_OPTION_INFRARED, + ++ CS2_OPTION_SAMPLES_PER_SCAN, ++ + CS2_OPTION_DEPTH, + + CS2_OPTION_EXPOSURE, +@@ -249,8 +251,8 @@ typedef struct + + /* settings */ + SANE_Bool preview, negative, infrared; +- int depth, real_depth, bytes_per_pixel, shift_bits, n_colour_in, +- n_colour_out; ++ int samples_per_scan, depth, real_depth, bytes_per_pixel, shift_bits, ++ n_colour_in, n_colour_out; + cs2_pixel_t n_lut; + cs2_pixel_t *lut_r, *lut_g, *lut_b, *lut_neutral; + unsigned long resx, resy, res, res_independent, res_preview; +@@ -508,6 +510,29 @@ sane_open (SANE_String_Const name, SANE_Handle * h) + o.size = WSIZE; + o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + break; ++ case CS2_OPTION_SAMPLES_PER_SCAN: ++ o.name = "samples-per-scan"; ++ o.title = "Samples per Scan"; ++ o.desc = "Number of samples per scan"; ++ o.type = SANE_TYPE_INT; ++ o.unit = SANE_UNIT_NONE; ++ o.size = WSIZE; ++ o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; ++ if (s->type != CS2_TYPE_LS2000 && s->type != CS2_TYPE_LS4000 ++ && s->type != CS2_TYPE_LS5000 && s->type != CS2_TYPE_LS8000) ++ o.cap |= SANE_CAP_INACTIVE; ++ o.constraint_type = SANE_CONSTRAINT_RANGE; ++ range = (SANE_Range *) cs2_xmalloc (sizeof (SANE_Range)); ++ if (! range) ++ alloc_failed = 1; ++ else ++ { ++ range->min = 1; ++ range->max = 16; ++ range->quant = 1; ++ o.constraint.range = range; ++ } ++ break; + case CS2_OPTION_DEPTH: + o.name = "depth"; + o.title = "Bit depth per channel"; +@@ -994,6 +1019,7 @@ sane_open (SANE_String_Const name, SANE_Handle * h) + s->negative = SANE_FALSE; + s->depth = 8; + s->infrared = 0; ++ s->samples_per_scan = 1; + s->i_frame = 1; + s->subframe = 0.; + s->res = s->resx = s->resx_max; +@@ -1080,6 +1106,9 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action a, void *v, + case CS2_OPTION_INFRARED: + *(SANE_Word *) v = s->infrared; + break; ++ case CS2_OPTION_SAMPLES_PER_SCAN: ++ *(SANE_Word *) v = s->samples_per_scan; ++ break; + case CS2_OPTION_DEPTH: + *(SANE_Word *) v = s->depth; + break; +@@ -1231,6 +1260,9 @@ sane_control_option (SANE_Handle h, SANE_Int n, SANE_Action a, void *v, + s->infrared = *(SANE_Word *) v; + /* flags |= SANE_INFO_RELOAD_PARAMS; XXXXXXXXXXXXXXXXX */ + break; ++ case CS2_OPTION_SAMPLES_PER_SCAN: ++ s->samples_per_scan = *(SANE_Word *) v; ++ break; + case CS2_OPTION_DEPTH: + s->depth = *(SANE_Word *) v; + flags |= SANE_INFO_RELOAD_PARAMS; +@@ -1462,9 +1494,10 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + SANE_Status status; + ssize_t xfer_len_in, xfer_len_line, xfer_len_out; + unsigned long index; +- int colour; ++ int colour, n_colours, sample_pass; + uint8_t *s8 = NULL; + uint16_t *s16 = NULL; ++ double m_avg_sum; + SANE_Byte *line_buf_new; + + DBG (10, "sane_read() called, maxlen = %i.\n", maxlen); +@@ -1554,6 +1587,9 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + s->n_line_buf = xfer_len_line; + } + ++ /* adapt for multi-sampling */ ++ xfer_len_in *= s->samples_per_scan; ++ + cs2_scanner_ready (s, CS2_STATUS_READY); + cs2_init_buffer (s); + cs2_parse_cmd (s, "28 00 00 00 00 00"); +@@ -1570,24 +1606,44 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + return status; + } + ++ n_colours = s->n_colour_out + ++ (s->infrared_stage == CS2_INFRARED_IN ? 1 : 0); ++ + for (index = 0; index < s->logical_width; index++) +- for (colour = 0; +- colour < s->n_colour_out + (s->infrared_stage == +- CS2_INFRARED_IN ? 1 : 0); colour++) ++ for (colour = 0; colour < n_colours; colour++) { ++ m_avg_sum = 0.0; + switch (s->bytes_per_pixel) + { + case 1: ++ /* calculate target address */ + if ((s->infrared_stage == CS2_INFRARED_IN) + && (colour == s->n_colour_out)) + s8 = (uint8_t *) & (s->infrared_buf[s->infrared_index++]); + else + s8 = + (uint8_t *) & (s->line_buf[s->n_colour_out * index + colour]); +- *s8 = +- s->recv_buf[colour * s->logical_width + +- (colour + 1) * s->odd_padding + index]; ++ ++ if (s->samples_per_scan > 1) ++ { ++ /* calculate average of multi samples */ ++ for (sample_pass = 0; ++ sample_pass < s->samples_per_scan; ++ sample_pass++) ++ m_avg_sum += (double) ++ s->recv_buf[s->logical_width * ++ (sample_pass * n_colours + colour) + ++ (colour + 1) * s->odd_padding + index]; ++ ++ *s8 = (uint8_t) (m_avg_sum / s->samples_per_scan + 0.5); ++ } ++ else ++ /* shortcut for single sample */ ++ *s8 = ++ s->recv_buf[colour * s->logical_width + ++ (colour + 1) * s->odd_padding + index]; + break; + case 2: ++ /* calculate target address */ + if ((s->infrared_stage == CS2_INFRARED_IN) + && (colour == s->n_colour_out)) + s16 = +@@ -1597,9 +1653,24 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + (uint16_t *) & (s-> + line_buf[2 * + (s->n_colour_out * index + colour)]); +- *s16 = +- s->recv_buf[2 * (colour * s->logical_width + index)] * 256 + +- s->recv_buf[2 * (colour * s->logical_width + index) + 1]; ++ ++ if (s->samples_per_scan > 1) ++ { ++ /* calculate average of multi samples */ ++ for (sample_pass = 0; ++ s->samples_per_scan > 1 && sample_pass < s->samples_per_scan; ++ sample_pass++) ++ m_avg_sum += (double) ++ (s->recv_buf[2 * (s->logical_width * (sample_pass * n_colours + colour) + index)] * 256 + ++ s->recv_buf[2 * (s->logical_width * (sample_pass * n_colours + colour) + index) + 1]); ++ ++ *s16 = (uint16_t) (m_avg_sum / s->samples_per_scan + 0.5); ++ } ++ else ++ /* shortcut for single sample */ ++ *s16 = ++ s->recv_buf[2 * (colour * s->logical_width + index)] * 256 + ++ s->recv_buf[2 * (colour * s->logical_width + index) + 1]; + *s16 <<= s->shift_bits; + break; + default: +@@ -1608,6 +1679,7 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + return SANE_STATUS_INVAL; + break; + } ++ } + s->xfer_position += xfer_len_line; + + xfer_len_out = xfer_len_line; +@@ -2870,7 +2942,7 @@ cs2_scan (cs2_t * s, cs2_scan_t type) + cs2_pack_byte (s, 0x05); /* image composition CCCCCCC */ + cs2_pack_byte (s, s->real_depth); /* pixel composition */ + cs2_parse_cmd (s, "00 00 00 00 00 00 00 00 00 00 00 00 00"); +- cs2_pack_byte (s, 0x00); /* multiread, ordering */ ++ cs2_pack_byte (s, ((s->samples_per_scan - 1) << 4) + 0x00); /* multiread, ordering */ + /* No need to use an undocumented bit in LS50 */ + if ((s->type == CS2_TYPE_LS50) || (s->type == CS2_TYPE_LS5000)) + cs2_pack_byte (s, 0x00 + (s->negative ? 0 : 1)); /* averaging, pos/neg */ +@@ -2892,7 +2964,10 @@ cs2_scan (cs2_t * s, cs2_scan_t type) + DBG (1, "BUG: cs2_scan(): Unknown scanning type.\n"); + return SANE_STATUS_INVAL; + } +- cs2_pack_byte (s, 0x02); /* scanning mode */ ++ if (s->samples_per_scan == 1) ++ cs2_pack_byte (s, 0x02); /* scanning mode single */ ++ else ++ cs2_pack_byte (s, 0x10); /* scanning mode multi */ + cs2_pack_byte (s, 0x02); /* colour interleaving */ + cs2_pack_byte (s, 0xff); /* (ae) */ + if (i_colour == 3) /* infrared */ +diff --git a/backend/coolscan3.c b/backend/coolscan3.c +index eca357c..a1d6fe6 100644 +--- a/backend/coolscan3.c ++++ b/backend/coolscan3.c +@@ -115,6 +115,8 @@ typedef enum + + CS3_OPTION_INFRARED, + ++ CS3_OPTION_SAMPLES_PER_SCAN, ++ + CS3_OPTION_DEPTH, + + CS3_OPTION_EXPOSURE, +@@ -212,7 +214,8 @@ typedef struct + + /* settings */ + SANE_Bool preview, negative, infrared, autoload, autofocus, ae, aewb; +- int depth, real_depth, bytes_per_pixel, shift_bits, n_colors; ++ int samples_per_scan, depth, real_depth, bytes_per_pixel, shift_bits, ++ n_colors; + cs3_pixel_t n_lut; + cs3_pixel_t *lut_r, *lut_g, *lut_b, *lut_neutral; + unsigned long resx, resy, res, res_independent, res_preview; +@@ -463,6 +466,30 @@ sane_open(SANE_String_Const name, SANE_Handle * h) + #endif + break; + ++ case CS3_OPTION_SAMPLES_PER_SCAN: ++ o.name = "samples-per-scan"; ++ o.title = "Samples per Scan"; ++ o.desc = "Number of samples per scan"; ++ o.type = SANE_TYPE_INT; ++ o.unit = SANE_UNIT_NONE; ++ o.size = WSIZE; ++ o.cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; ++ if (s->type != CS3_TYPE_LS2000 && s->type != CS3_TYPE_LS4000 ++ && s->type != CS3_TYPE_LS5000 && s->type != CS3_TYPE_LS8000) ++ o.cap |= SANE_CAP_INACTIVE; ++ o.constraint_type = SANE_CONSTRAINT_RANGE; ++ range = (SANE_Range *) cs3_xmalloc (sizeof (SANE_Range)); ++ if (! range) ++ alloc_failed = 1; ++ else ++ { ++ range->min = 1; ++ range->max = 16; ++ range->quant = 1; ++ o.constraint.range = range; ++ } ++ break; ++ + case CS3_OPTION_DEPTH: + o.name = "depth"; + o.title = "Bit depth per channel"; +@@ -983,6 +1010,7 @@ sane_open(SANE_String_Const name, SANE_Handle * h) + s->infrared = SANE_FALSE; + s->ae = SANE_FALSE; + s->aewb = SANE_FALSE; ++ s->samples_per_scan = 1; + s->depth = 8; + s->i_frame = 1; + s->frame_count = 1; +@@ -1064,6 +1092,9 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, + case CS3_OPTION_INFRARED: + *(SANE_Word *) v = s->infrared; + break; ++ case CS3_OPTION_SAMPLES_PER_SCAN: ++ *(SANE_Word *) v = s->samples_per_scan; ++ break; + case CS3_OPTION_DEPTH: + *(SANE_Word *) v = s->depth; + break; +@@ -1222,6 +1253,9 @@ sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, + s->infrared = *(SANE_Word *) v; + /* flags |= SANE_INFO_RELOAD_PARAMS; XXX */ + break; ++ case CS3_OPTION_SAMPLES_PER_SCAN: ++ s->samples_per_scan = *(SANE_Word *) v; ++ break; + case CS3_OPTION_DEPTH: + if (*(SANE_Word *) v > s->maxbits) + return SANE_STATUS_INVAL; +@@ -1487,9 +1521,10 @@ sane_read(SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + SANE_Status status; + ssize_t xfer_len_in, xfer_len_line, xfer_len_out; + unsigned long index; +- int color; ++ int color, sample_pass; + uint8_t *s8 = NULL; + uint16_t *s16 = NULL; ++ double m_avg_sum; + SANE_Byte *line_buf_new; + + DBG(32, "%s, maxlen = %i.\n", __func__, maxlen); +@@ -1567,6 +1602,9 @@ sane_read(SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + s->n_line_buf = xfer_len_line; + } + ++ /* adapt for multi-sampling */ ++ xfer_len_in *= s->samples_per_scan; ++ + cs3_scanner_ready(s, CS3_STATUS_READY); + cs3_init_buffer(s); + cs3_parse_cmd(s, "28 00 00 00 00 00"); +@@ -1584,30 +1622,63 @@ sane_read(SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) + + for (index = 0; index < s->logical_width; index++) { + for (color = 0; color < s->n_colors; color++) { +- + int where = s->bytes_per_pixel + * (s->n_colors * index + color); + ++ m_avg_sum = 0.0; ++ + switch (s->bytes_per_pixel) { + case 1: + { +- int p8 = color * s->logical_width +- + (color + 1) * s->odd_padding +- + index; +- ++ /* target address */ + s8 = (uint8_t *) & (s->line_buf[where]); +- *s8 = s->recv_buf[p8]; ++ ++ if (s->samples_per_scan > 1) { ++ /* calculate average of multi samples */ ++ for (sample_pass = 0; ++ sample_pass < s->samples_per_scan; ++ sample_pass++) { ++ /* source index */ ++ int p8 = (sample_pass * s->n_colors + color) ++ * s->logical_width ++ + (color + 1) * s->odd_padding ++ + index; ++ m_avg_sum += (double) s->recv_buf[p8]; ++ } ++ *s8 = (uint8_t) (m_avg_sum / s->samples_per_scan + 0.5); ++ } else { ++ /* shortcut for single sample */ ++ int p8 = s->logical_width * color ++ + (color + 1) * s->odd_padding ++ + index; ++ *s8 = s->recv_buf[p8]; ++ } + } + break; + case 2: + { +- int p16 = +- 2 * (color * s->logical_width + +- index); +- ++ /* target address */ + s16 = (uint16_t *) & (s->line_buf[where]); +- *s16 = (s->recv_buf[p16] << 8) +- + s->recv_buf[p16 + 1]; ++ ++ if (s->samples_per_scan > 1) { ++ /* calculate average of multi samples */ ++ for (sample_pass = 0; ++ sample_pass < s->samples_per_scan; ++ sample_pass++) { ++ /* source index */ ++ int p16 = 2 * ((sample_pass * s->n_colors + color) ++ * s->logical_width + index); ++ m_avg_sum += (double) ((s->recv_buf[p16] << 8) ++ + s->recv_buf[p16 + 1]); ++ } ++ *s16 = (uint16_t) (m_avg_sum / s->samples_per_scan + 0.5); ++ } else { ++ /* shortcut for single sample */ ++ int p16 = 2 * (color * s->logical_width + index); ++ ++ *s16 = (s->recv_buf[p16] << 8) ++ + s->recv_buf[p16 + 1]; ++ } + + *s16 <<= s->shift_bits; + } +@@ -2955,7 +3026,7 @@ cs3_set_window(cs3_t * s, cs3_scan_t type) + cs3_pack_byte(s, 0x05); /* image composition CCCCCCC */ + cs3_pack_byte(s, s->real_depth); /* pixel composition */ + cs3_parse_cmd(s, "00 00 00 00 00 00 00 00 00 00 00 00 00"); +- cs3_pack_byte(s, 0x00); /* multiread, ordering */ ++ cs3_pack_byte(s, ((s->samples_per_scan - 1) << 4) | 0x00); /* multiread, ordering */ + + cs3_pack_byte(s, 0x80 | (s->negative ? 0 : 1)); /* averaging, pos/neg */ + +@@ -2973,7 +3044,10 @@ cs3_set_window(cs3_t * s, cs3_scan_t type) + DBG(1, "BUG: cs3_scan(): Unknown scanning type.\n"); + return SANE_STATUS_INVAL; + } +- cs3_pack_byte(s, 0x02); /* scanning mode */ ++ if (s->samples_per_scan == 1) ++ cs3_pack_byte(s, 0x02); /* scanning mode single */ ++ else ++ cs3_pack_byte(s, 0x10); /* scanning mode multi */ + cs3_pack_byte(s, 0x02); /* color interleaving */ + cs3_pack_byte(s, 0xff); /* (ae) */ + if (color == 3) /* infrared */ +-- +1.8.1 + diff --git a/sane-backends.spec b/sane-backends.spec index 59e7e19..b1cf5f2 100644 --- a/sane-backends.spec +++ b/sane-backends.spec @@ -43,6 +43,8 @@ Patch3: sane-backends-1.0.23-soname.patch Patch4: sane-backends-1.0.23-sane-config-multilib.patch # Submitted upstream: don't barf on umax init errors Patch5: sane-backends-1.0.23-umax-init-error.patch +# Submitted upstream: coolscan2/3: support multi-scan option of some devices +Patch6: sane-backends-1.0.23-coolscan-multiscan.patch URL: http://www.sane-project.org @@ -134,6 +136,7 @@ This package contains backend drivers to access digital cameras through SANE. %patch3 -p1 -b .soname %patch4 -p1 -b .sane-config-multilib %patch5 -p1 -b .umax-init-error +%patch6 -p1 -b .coolscan-multiscan %build %if ! 0%{?_hardened_build} @@ -220,6 +223,7 @@ install -m 0644 tools/sane-backends.pc %{buildroot}%{_libdir}/pkgconfig/ - filter out backend driver provides/requires - update latex build dep - umax: initialize reader_pid early in sane_start() (#853667) +- coolscan2/3: support multi-scan option of some devices * Mon Jan 21 2013 Adam Tkac - 1.0.23-6 - rebuild due to "jpeg8-ABI" feature drop