From b82e9949b58b6faa346a2a5a6ccf35a6337a0aa6 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Sat, 29 Jan 2011 11:50:13 +0900 Subject: [PATCH] Fixed back page handling for flipping duplexers Although the flipping duplexer is working, there are some issues relating to the mechanics of physically flipping paper. First among these is that the back side of each page is physically scanned in reverse, resulting in an upside down image. Secondly, the page is held partially in the ADF mechanism while waiting for the frontend to make another scan request for the back side image, thus resulting in a stuck page if the frontend fails to follow through. My solution to these problems is to treat page flipping as an extreme extension of interlaced scanning; page level interlacing. This means making another scan request on behalf of the frontend, and writing the resulting image to a file as would have been done if the page were line interlaced. We would have had to write this image to a file anyway to flip the image right-side up, so we aren't doing any extra work, and technique allows us to reuse existing code for most of the file handling. The reader_process() function is called again (recursively) after scanning the front page. We use the page length of the front side to determine the length of the back, so that we can write the lines to the file starting at the end and working towards the beginning (thus flipping the image). A side effect of this solution was the discovery that the scanner must be reminded that the paper needs to be re-flipped after each scan, so set_window() must also be called in reader_process() before starting the second scan. Finally, with this change, a minor bug was exposed where frontends were given the number of lines which would be scanned, which makes sense in flatbed mode, but does not make sense for an ADF, where the page may be smaller than the scan window. The code was changed to follow the specifications, returning -1 in ADF mode (when the length cannot be determined). --- backend/avision.c | 59 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/backend/avision.c b/backend/avision.c index 3a1d82461..ce5f72f2d 100644 --- a/backend/avision.c +++ b/backend/avision.c @@ -2596,6 +2596,9 @@ compute_parameters (Avision_Scanner* s) s->params.pixels_per_line = s->avdimen.hw_pixels_per_line * s->avdimen.xres / s->avdimen.hw_xres; s->params.lines = s->avdimen.hw_lines * s->avdimen.xres / s->avdimen.hw_xres; + if (!is_adf_scan (s)) + /* we can't know how many lines we'll see with an ADF because that depends on the paper length */ + s->params.lines = -1; if (s->c_mode == AV_THRESHOLDED || s->c_mode == AV_DITHERED) s->params.pixels_per_line -= s->params.pixels_per_line % 8; @@ -6170,7 +6173,8 @@ do_eof (Avision_Scanner *s) s->prepared = s->scanning = SANE_FALSE; /* we can now mark the rear data as valid */ - if (s->avdimen.interlaced_duplex) { + if (s->avdimen.interlaced_duplex || + (s->hw->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX)) { DBG (3, "do_eof: toggling duplex rear data valid\n"); s->duplex_rear_valid = !s->duplex_rear_valid; DBG (3, "do_eof: duplex rear data valid: %x\n", @@ -6757,7 +6761,7 @@ reader_process (void *data) return SANE_STATUS_NO_MEM; /* start scan ? */ - if (deinterlace == NONE || + if ((deinterlace == NONE && !((dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->duplex_rear_valid)) || (deinterlace != NONE && !s->duplex_rear_valid)) { /* reserve unit - in the past we did this in open - but the @@ -6793,8 +6797,9 @@ reader_process (void *data) } } - /* setup file i/o for deinterlacing scans */ - if (deinterlace != NONE) + /* setup file i/o for deinterlacing scans or if we are the back page with a flipping duplexer */ + if (deinterlace != NONE || + (dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2))) { if (!s->duplex_rear_valid) { /* create new file for writing */ DBG (3, "reader_process: opening duplex rear file for writing.\n"); @@ -7021,6 +7026,21 @@ reader_process (void *data) DBG (9, "reader_process: after deinterlacing: useful_bytes: %d, stripe_fill: %d\n", useful_bytes, stripe_fill); } + if (dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2) && !s->duplex_rear_valid) { + /* Here we flip the image by writing the lines from the end of the file to the beginning. */ + unsigned int absline = (processed_bytes - stripe_fill) / s->avdimen.hw_bytes_per_line; + unsigned int abslines = absline + useful_bytes / s->avdimen.hw_bytes_per_line; + uint8_t* ptr = stripe_data; + for ( ; absline < abslines; ++absline) { + fseek (rear_fp, (s->params.lines - absline + 1) * s->avdimen.hw_bytes_per_line, SEEK_SET); + fwrite (ptr, s->avdimen.hw_bytes_per_line, 1, rear_fp); + useful_bytes -= s->avdimen.hw_bytes_per_line; + stripe_fill -= s->avdimen.hw_bytes_per_line; + ptr += s->avdimen.hw_bytes_per_line; + } + DBG (9, "reader_process: after page flip: useful_bytes: %d, stripe_fill: %d\n", + useful_bytes, stripe_fill); + } /* * Perform needed data conversions (packing, ...) and/or copy the @@ -7228,7 +7248,7 @@ reader_process (void *data) /* on-the-fly bi-linear interpolation */ while (1) { - double by = (-1.0 + s->avdimen.hw_lines) * line / s->params.lines; + double by = (-1.0 + s->avdimen.hw_lines) * line / (s->avdimen.hw_lines * s->avdimen.xres / s->avdimen.hw_xres + s->val[OPT_BACKGROUND].w); int sy = (int)floor(by); int ydist = (int) ((by - sy) * 256); int syy = sy + 1; @@ -7411,7 +7431,8 @@ reader_process (void *data) /* Eject film holder and/or release_unit - but only for non-duplex-rear / non-virtual scans. */ - if (deinterlace != NONE && s->duplex_rear_valid) + if ((deinterlace != NONE && s->duplex_rear_valid) || + ((dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2) && s->duplex_rear_valid)) { DBG (1, "reader_process: virtual duplex scan - no device cleanup!\n"); } @@ -7434,7 +7455,28 @@ reader_process (void *data) } } - fclose (fp); + if ((dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->page % 2) { + /* front page of flipping duplex */ + if (exit_status == SANE_STATUS_EOF) { + status = set_window (s); + if (status != SANE_STATUS_GOOD) { + DBG (1, "reader_process: set scan window command failed: %s\n", + sane_strstatus (status)); + return status; + } + /* we can set anything here without fear because the process will terminate soon and take our changes with it */ + s->page += 1; + s->params.lines = line; + exit_status = reader_process (s); + } + /* TODO: + * else { + * spit out the page if an error was encountered... + * assuming the error won't prevent it. + * } */ + } else { + fclose (fp); + } if (rear_fp) fclose (rear_fp); @@ -7819,7 +7861,8 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) /* initialize the options */ init_options (s); - if (dev->inquiry_duplex_interlaced || dev->scanner_type == AV_FILM) { + if (dev->inquiry_duplex_interlaced || dev->scanner_type == AV_FILM || + dev->hw->feature_type2 & AV_ADF_FLIPPING_DUPLEX) { /* Might need at least *DOS (Windows flavour and OS/2) portability fix However, I was told Cygwin (et al.) takes care of it. */ strncpy(s->duplex_rear_fname, "/tmp/avision-rear-XXXXXX", PATH_MAX);