summaryrefslogtreecommitdiff
path: root/backend/hp5590.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/hp5590.c')
-rw-r--r--backend/hp5590.c2150
1 files changed, 1670 insertions, 480 deletions
diff --git a/backend/hp5590.c b/backend/hp5590.c
index fabf40a..b206406 100644
--- a/backend/hp5590.c
+++ b/backend/hp5590.c
@@ -1,6 +1,8 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2007 Ilia Sotnikov <hostcc@gmail.com>
HP ScanJet 4570c support by Markham Thomas
+ ADF page detection and high DPI fixes by Bernard Badeer
+ scanbd integration by Damiano Scaramuzza and Bernard Badeer
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
@@ -59,47 +61,161 @@
#include "../include/sane/saneopts.h"
#include "hp5590_cmds.c"
#include "hp5590_low.c"
+#include "../include/sane/sanei_net.h"
/* Debug levels */
-#define DBG_err 0
-#define DBG_proc 10
-#define DBG_verbose 20
+#define DBG_err 0
+#define DBG_proc 10
+#define DBG_verbose 20
+#define DBG_details 30
#define hp5590_assert(exp) if(!(exp)) { \
- DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
- return SANE_STATUS_INVAL; \
+ DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
+ return SANE_STATUS_INVAL; \
}
#define hp5590_assert_void_return(exp) if(!(exp)) { \
- DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
- return; \
+ DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\
+ return; \
}
+#define MY_MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MY_MAX(a, b) (((a) > (b)) ? (a) : (b))
+
/* #define HAS_WORKING_COLOR_48 */
-#define BUILD 7
-#define USB_TIMEOUT 30 * 1000
+#define BUILD 8
+#define USB_TIMEOUT 30 * 1000
static SANE_Word
res_list[] = { 6, 100, 200, 300, 600, 1200, 2400 };
-#define SANE_VALUE_SCAN_SOURCE_FLATBED SANE_I18N("Flatbed")
-#define SANE_VALUE_SCAN_SOURCE_ADF SANE_I18N("ADF")
-#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX SANE_I18N("ADF Duplex")
-#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES SANE_I18N("TMA Slides")
-#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES SANE_I18N("TMA Negatives")
+#define SANE_VALUE_SCAN_SOURCE_FLATBED SANE_I18N("Flatbed")
+#define SANE_VALUE_SCAN_SOURCE_ADF SANE_I18N("ADF")
+#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX SANE_I18N("ADF Duplex")
+#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES SANE_I18N("TMA Slides")
+#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES SANE_I18N("TMA Negatives")
+static SANE_String_Const
+sources_list[] = {
+ SANE_VALUE_SCAN_SOURCE_FLATBED,
+ SANE_VALUE_SCAN_SOURCE_ADF,
+ SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX,
+ SANE_VALUE_SCAN_SOURCE_TMA_SLIDES,
+ SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES,
+ NULL
+};
+
+#define SANE_VALUE_SCAN_MODE_COLOR_24 SANE_VALUE_SCAN_MODE_COLOR
+#define SANE_VALUE_SCAN_MODE_COLOR_48 SANE_I18N("Color (48 bits)")
+#define HAS_WORKING_COLOR_48 1
+
+#define SANE_NAME_LAMP_TIMEOUT "extend-lamp-timeout"
+#define SANE_TITLE_LAMP_TIMEOUT SANE_I18N("Extend lamp timeout")
+#define SANE_DESC_LAMP_TIMEOUT SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)")
+#define SANE_NAME_WAIT_FOR_BUTTON "wait-for-button"
+#define SANE_TITLE_WAIT_FOR_BUTTON SANE_I18N("Wait for button")
+#define SANE_DESC_WAIT_FOR_BUTTON SANE_I18N("Waits for button before scanning")
+#define SANE_NAME_BUTTON_PRESSED "button-pressed"
+#define SANE_TITLE_BUTTON_PRESSED SANE_I18N("Last button pressed")
+#define SANE_DESC_BUTTON_PRESSED SANE_I18N("Get ID of last button pressed (read only)")
+#define SANE_NAME_LCD_COUNTER "counter-value"
+#define SANE_TITLE_LCD_COUNTER SANE_I18N("LCD counter")
+#define SANE_DESC_LCD_COUNTER SANE_I18N("Get value of LCD counter (read only)")
+#define SANE_NAME_COLOR_LED "color-led"
+#define SANE_TITLE_COLOR_LED SANE_I18N("Color LED indicator")
+#define SANE_DESC_COLOR_LED SANE_I18N("Get value of LED indicator (read only)")
+#define SANE_NAME_DOC_IN_ADF "doc-in-adf"
+#define SANE_TITLE_DOC_IN_ADF SANE_I18N("Document available in ADF")
+#define SANE_DESC_DOC_IN_ADF SANE_I18N("Get state of document-available indicator in ADF (read only)")
+#define SANE_NAME_OVERWRITE_EOP_PIXEL "hide-eop-pixel"
+#define SANE_TITLE_OVERWRITE_EOP_PIXEL SANE_I18N("Hide end-of-page pixel")
+#define SANE_DESC_OVERWRITE_EOP_PIXEL SANE_I18N("Hide end-of-page indicator pixels and overwrite with neighbor pixels")
+#define SANE_NAME_TRAILING_LINES_MODE "trailing-lines-mode"
+#define SANE_TITLE_TRAILING_LINES_MODE SANE_I18N("Filling mode of trailing lines after scan data (ADF)")
+#define SANE_DESC_TRAILING_LINES_MODE SANE_I18N("raw = raw scan data, last = repeat last scan line, raster = b/w raster, "\
+ "white = white color, black = black color, color = RGB or gray color value")
+#define SANE_NAME_TRAILING_LINES_COLOR "trailing-lines-color"
+#define SANE_TITLE_TRAILING_LINES_COLOR SANE_I18N("RGB or gray color value for filling mode 'color'")
+#define SANE_DESC_TRAILING_LINES_COLOR SANE_I18N("Color value for trailing lines filling mode 'color'. "\
+ "RGB color as r*65536+256*g+b or gray value (default=violet or gray)")
+
+#define BUTTON_PRESSED_VALUE_COUNT 11
+#define BUTTON_PRESSED_VALUE_NONE_KEY "none"
+#define BUTTON_PRESSED_VALUE_POWER_KEY "power"
+#define BUTTON_PRESSED_VALUE_SCAN_KEY "scan"
+#define BUTTON_PRESSED_VALUE_COLLECT_KEY "collect"
+#define BUTTON_PRESSED_VALUE_FILE_KEY "file"
+#define BUTTON_PRESSED_VALUE_EMAIL_KEY "email"
+#define BUTTON_PRESSED_VALUE_COPY_KEY "copy"
+#define BUTTON_PRESSED_VALUE_UP_KEY "up"
+#define BUTTON_PRESSED_VALUE_DOWN_KEY "down"
+#define BUTTON_PRESSED_VALUE_MODE_KEY "mode"
+#define BUTTON_PRESSED_VALUE_CANCEL_KEY "cancel"
+#define BUTTON_PRESSED_VALUE_MAX_KEY_LEN 32
+static SANE_String_Const
+buttonstate_list[] = {
+ BUTTON_PRESSED_VALUE_NONE_KEY,
+ BUTTON_PRESSED_VALUE_POWER_KEY,
+ BUTTON_PRESSED_VALUE_SCAN_KEY,
+ BUTTON_PRESSED_VALUE_COLLECT_KEY,
+ BUTTON_PRESSED_VALUE_FILE_KEY,
+ BUTTON_PRESSED_VALUE_EMAIL_KEY,
+ BUTTON_PRESSED_VALUE_COPY_KEY,
+ BUTTON_PRESSED_VALUE_UP_KEY,
+ BUTTON_PRESSED_VALUE_DOWN_KEY,
+ BUTTON_PRESSED_VALUE_MODE_KEY,
+ BUTTON_PRESSED_VALUE_CANCEL_KEY,
+ NULL
+};
+
+#define COLOR_LED_VALUE_COUNT 2
+#define COLOR_LED_VALUE_COLOR_KEY "color"
+#define COLOR_LED_VALUE_BLACKWHITE_KEY "black_white"
+#define COLOR_LED_VALUE_MAX_KEY_LEN 32
+static SANE_String_Const
+colorledstate_list[] = {
+ COLOR_LED_VALUE_COLOR_KEY,
+ COLOR_LED_VALUE_BLACKWHITE_KEY,
+ NULL
+};
-#define SANE_VALUE_SCAN_MODE_COLOR_24 SANE_VALUE_SCAN_MODE_COLOR
-#define SANE_VALUE_SCAN_MODE_COLOR_48 SANE_I18N("Color (48 bits)")
+#define LCD_COUNTER_VALUE_MIN 1
+#define LCD_COUNTER_VALUE_MAX 99
+#define LCD_COUNTER_VALUE_QUANT 1
+static SANE_Range
+lcd_counter_range = {
+ LCD_COUNTER_VALUE_MIN,
+ LCD_COUNTER_VALUE_MAX,
+ LCD_COUNTER_VALUE_QUANT
+};
-#define SANE_NAME_LAMP_TIMEOUT "extend-lamp-timeout"
-#define SANE_TITLE_LAMP_TIMEOUT SANE_I18N("Extend lamp timeout")
-#define SANE_DESC_LAMP_TIMEOUT SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)")
-#define SANE_NAME_WAIT_FOR_BUTTON "wait-for-button"
-#define SANE_TITLE_WAIT_FOR_BUTTON SANE_I18N("Wait for button")
-#define SANE_DESC_WAIT_FOR_BUTTON SANE_I18N("Waits for button before scanning")
+#define TRAILING_LINES_MODE_RAW 0
+#define TRAILING_LINES_MODE_LAST 1
+#define TRAILING_LINES_MODE_RASTER 2
+#define TRAILING_LINES_MODE_WHITE 3
+#define TRAILING_LINES_MODE_BLACK 4
+#define TRAILING_LINES_MODE_COLOR 5
+#define TRAILING_LINES_MODE_VALUE_COUNT 6
+
+#define TRAILING_LINES_MODE_RAW_KEY "raw"
+#define TRAILING_LINES_MODE_LAST_KEY "last"
+#define TRAILING_LINES_MODE_RASTER_KEY "raster"
+#define TRAILING_LINES_MODE_WHITE_KEY "white"
+#define TRAILING_LINES_MODE_BLACK_KEY "black"
+#define TRAILING_LINES_MODE_COLOR_KEY "color"
+#define TRAILING_LINES_MODE_MAX_KEY_LEN 24
+static SANE_String_Const
+trailingmode_list[] = {
+ TRAILING_LINES_MODE_RAW_KEY,
+ TRAILING_LINES_MODE_LAST_KEY,
+ TRAILING_LINES_MODE_RASTER_KEY,
+ TRAILING_LINES_MODE_WHITE_KEY,
+ TRAILING_LINES_MODE_BLACK_KEY,
+ TRAILING_LINES_MODE_COLOR_KEY,
+ NULL
+};
-#define MAX_SCAN_SOURCE_VALUE_LEN 24
-#define MAX_SCAN_MODE_VALUE_LEN 24
+#define MAX_SCAN_SOURCE_VALUE_LEN 24
+#define MAX_SCAN_MODE_VALUE_LEN 24
static SANE_Range
range_x, range_y, range_qual;
@@ -126,29 +242,51 @@ enum hp5590_opt_idx {
HP5590_OPT_RESOLUTION,
HP5590_OPT_LAMP_TIMEOUT,
HP5590_OPT_WAIT_FOR_BUTTON,
+ HP5590_OPT_BUTTON_PRESSED,
+ HP5590_OPT_COLOR_LED,
+ HP5590_OPT_LCD_COUNTER,
+ HP5590_OPT_DOC_IN_ADF,
HP5590_OPT_PREVIEW,
+ HP5590_OPT_OVERWRITE_EOP_PIXEL,
+ HP5590_OPT_TRAILING_LINES_MODE,
+ HP5590_OPT_TRAILING_LINES_COLOR,
HP5590_OPT_LAST
};
struct hp5590_scanner {
- struct scanner_info *info;
- enum proto_flags proto_flags;
- SANE_Device sane;
- SANE_Int dn;
- float br_x, br_y, tl_x, tl_y;
- unsigned int dpi;
- enum color_depths depth;
- enum scan_sources source;
- SANE_Bool extend_lamp_timeout;
- SANE_Bool wait_for_button;
- SANE_Bool preview;
- unsigned int quality;
- SANE_Option_Descriptor *opts;
- struct hp5590_scanner *next;
- unsigned int image_size;
- SANE_Int transferred_image_size;
- void *bulk_read_state;
- SANE_Bool scanning;
+ struct scanner_info *info;
+ enum proto_flags proto_flags;
+ SANE_Device sane;
+ SANE_Int dn;
+ float br_x, br_y, tl_x, tl_y;
+ unsigned int dpi;
+ enum color_depths depth;
+ enum scan_sources source;
+ SANE_Bool extend_lamp_timeout;
+ SANE_Bool wait_for_button;
+ SANE_Bool preview;
+ unsigned int quality;
+ SANE_Option_Descriptor *opts;
+ struct hp5590_scanner *next;
+ unsigned long long image_size;
+ unsigned long long transferred_image_size;
+ void *bulk_read_state;
+ SANE_Bool scanning;
+ SANE_Bool overwrite_eop_pixel;
+ SANE_Byte *eop_last_line_data;
+ unsigned int eop_last_line_data_rpos;
+ SANE_Int eop_trailing_lines_mode;
+ SANE_Int eop_trailing_lines_color;
+ SANE_Byte *adf_next_page_lines_data;
+ unsigned int adf_next_page_lines_data_size;
+ unsigned int adf_next_page_lines_data_rpos;
+ unsigned int adf_next_page_lines_data_wpos;
+ SANE_Byte *one_line_read_buffer;
+ unsigned int one_line_read_buffer_rpos;
+ SANE_Byte *color_shift_line_buffer1;
+ unsigned int color_shift_buffered_lines1;
+ SANE_Byte *color_shift_line_buffer2;
+ unsigned int color_shift_buffered_lines2;
};
static
@@ -157,19 +295,19 @@ struct hp5590_scanner *scanners_list;
/******************************************************************************/
static SANE_Status
calc_image_params (struct hp5590_scanner *scanner,
- unsigned int *pixel_bits,
- unsigned int *pixels_per_line,
- unsigned int *bytes_per_line,
- unsigned int *lines,
- unsigned int *image_size)
+ unsigned int *pixel_bits,
+ unsigned int *pixels_per_line,
+ unsigned int *bytes_per_line,
+ unsigned int *lines,
+ unsigned long long *image_size)
{
- unsigned int _pixel_bits;
- SANE_Status ret;
- unsigned int _pixels_per_line;
- unsigned int _bytes_per_line;
- unsigned int _lines;
- unsigned int _image_size;
- float var;
+ unsigned int _pixel_bits;
+ SANE_Status ret;
+ unsigned int _pixels_per_line;
+ unsigned int _bytes_per_line;
+ unsigned int _lines;
+ unsigned int _image_size;
+ float var;
DBG (DBG_proc, "%s\n", __func__);
@@ -195,7 +333,7 @@ calc_image_params (struct hp5590_scanner *scanner,
if (var > _bytes_per_line)
_bytes_per_line++;
- _image_size = _lines * _bytes_per_line;
+ _image_size = (unsigned long long) _lines * _bytes_per_line;
DBG (DBG_verbose, "%s: pixel_bits: %u, pixels_per_line: %u, "
"bytes_per_line: %u, lines: %u, image_size: %u\n",
@@ -219,18 +357,18 @@ calc_image_params (struct hp5590_scanner *scanner,
return SANE_STATUS_GOOD;
}
-
+
/******************************************************************************/
static SANE_Status
attach_usb_device (SANE_String_Const devname,
- enum hp_scanner_types hp_scanner_type)
+ enum hp_scanner_types hp_scanner_type)
{
- struct scanner_info *info;
- struct hp5590_scanner *scanner, *ptr;
- unsigned int max_count, count;
- SANE_Int dn;
- SANE_Status ret;
- const struct hp5590_model *hp5590_model;
+ struct scanner_info *info;
+ struct hp5590_scanner *scanner, *ptr;
+ unsigned int max_count, count;
+ SANE_Int dn;
+ SANE_Status ret;
+ const struct hp5590_model *hp5590_model;
DBG (DBG_proc, "%s: Opening USB device\n", __func__);
if (sanei_usb_open (devname, &dn) != SANE_STATUS_GOOD)
@@ -242,7 +380,7 @@ attach_usb_device (SANE_String_Const devname,
return ret;
if (hp5590_init_scanner (dn, hp5590_model->proto_flags,
- &info, hp_scanner_type) != 0)
+ &info, hp_scanner_type) != 0)
return SANE_STATUS_IO_ERROR;
DBG (1, "%s: found HP%s scanner at '%s'\n",
@@ -250,13 +388,13 @@ attach_usb_device (SANE_String_Const devname,
DBG (DBG_verbose, "%s: Reading max scan count\n", __func__);
if (hp5590_read_max_scan_count (dn, hp5590_model->proto_flags,
- &max_count) != 0)
+ &max_count) != 0)
return SANE_STATUS_IO_ERROR;
DBG (DBG_verbose, "%s: Max Scanning count %u\n", __func__, max_count);
DBG (DBG_verbose, "%s: Reading scan count\n", __func__);
if (hp5590_read_scan_count (dn, hp5590_model->proto_flags,
- &count) != 0)
+ &count) != 0)
return SANE_STATUS_IO_ERROR;
DBG (DBG_verbose, "%s: Scanning count %u\n", __func__, count);
@@ -282,6 +420,18 @@ attach_usb_device (SANE_String_Const devname,
scanner->info = info;
scanner->bulk_read_state = NULL;
scanner->opts = NULL;
+ scanner->eop_last_line_data = NULL;
+ scanner->eop_last_line_data_rpos = 0;
+ scanner->adf_next_page_lines_data = NULL;
+ scanner->adf_next_page_lines_data_size = 0;
+ scanner->adf_next_page_lines_data_rpos = 0;
+ scanner->adf_next_page_lines_data_wpos = 0;
+ scanner->one_line_read_buffer = NULL;
+ scanner->one_line_read_buffer_rpos = 0;
+ scanner->color_shift_line_buffer1 = NULL;
+ scanner->color_shift_buffered_lines1 = 0;
+ scanner->color_shift_line_buffer2 = NULL;
+ scanner->color_shift_buffered_lines2 = 0;
if (!scanners_list)
scanners_list = scanner;
@@ -326,11 +476,11 @@ attach_hp7650 (SANE_String_Const devname)
SANE_Status
sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize)
{
- SANE_Status ret;
- SANE_Word vendor_id, product_id;
-
+ SANE_Status ret;
+ SANE_Word vendor_id, product_id;
+
DBG_INIT();
-
+
DBG (1, "SANE backed for HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 %u.%u.%u\n",
SANE_CURRENT_MAJOR, V_MINOR, BUILD);
DBG (1, "(c) Ilia Sotnikov <hostcc@gmail.com>\n");
@@ -389,7 +539,34 @@ void sane_exit (void)
for (ptr = scanners_list; ptr; ptr = pnext)
{
if (ptr->opts != NULL)
- free (ptr->opts);
+ free (ptr->opts);
+ if (ptr->eop_last_line_data != NULL) {
+ free (ptr->eop_last_line_data);
+ ptr->eop_last_line_data = NULL;
+ ptr->eop_last_line_data_rpos = 0;
+ }
+ if (ptr->adf_next_page_lines_data != NULL) {
+ free (ptr->adf_next_page_lines_data);
+ ptr->adf_next_page_lines_data = NULL;
+ ptr->adf_next_page_lines_data_size = 0;
+ ptr->adf_next_page_lines_data_wpos = 0;
+ ptr->adf_next_page_lines_data_rpos = 0;
+ }
+ if (ptr->one_line_read_buffer != NULL) {
+ free (ptr->one_line_read_buffer);
+ ptr->one_line_read_buffer = NULL;
+ ptr->one_line_read_buffer_rpos = 0;
+ }
+ if (ptr->color_shift_line_buffer1 != NULL) {
+ free (ptr->color_shift_line_buffer1);
+ ptr->color_shift_line_buffer1 = NULL;
+ ptr->color_shift_buffered_lines1 = 0;
+ }
+ if (ptr->color_shift_line_buffer2 != NULL) {
+ free (ptr->color_shift_line_buffer2);
+ ptr->color_shift_line_buffer2 = NULL;
+ ptr->color_shift_buffered_lines2 = 0;
+ }
pnext = ptr->next;
free (ptr);
}
@@ -428,11 +605,8 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
SANE_Status
sane_open (SANE_String_Const devicename, SANE_Handle * handle)
{
- struct hp5590_scanner *ptr;
- SANE_Option_Descriptor *opts;
- unsigned int available_sources;
- SANE_String_Const *sources_list;
- unsigned int source_idx;
+ struct hp5590_scanner *ptr;
+ SANE_Option_Descriptor *opts;
DBG (DBG_proc, "%s: device name: %s\n", __func__, devicename);
@@ -444,19 +618,31 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
ptr = scanners_list;
} else {
for (ptr = scanners_list;
- ptr && strcmp (ptr->sane.name, devicename) != 0;
- ptr = ptr->next);
+ ptr && strcmp (ptr->sane.name, devicename) != 0;
+ ptr = ptr->next);
}
if (!ptr)
return SANE_STATUS_INVAL;
+ /* DS: Without this after the first scan (and sane_close)
+ * it was impossible to use again the read_buttons usb routine.
+ * Function sane_close puts dn = -1. Now sane_open needs to open
+ * the usb communication again.
+ */
+ if (ptr->dn < 0) {
+ DBG (DBG_proc, "%s: Reopening USB device\n", __func__);
+ if (sanei_usb_open (ptr->sane.name, &ptr->dn) != SANE_STATUS_GOOD)
+ return SANE_STATUS_IO_ERROR;
+ DBG (DBG_proc, "%s: USB device reopened\n", __func__);
+ }
+
ptr->tl_x = 0;
ptr->tl_y = 0;
ptr->br_x = ptr->info->max_size_x;
ptr->br_y = ptr->info->max_size_y;
ptr->dpi = res_list[1];
- ptr->depth = DEPTH_BW;
+ ptr->depth = DEPTH_BW;
ptr->source = SOURCE_FLATBED;
ptr->extend_lamp_timeout = SANE_FALSE;
ptr->wait_for_button = SANE_FALSE;
@@ -464,6 +650,9 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
ptr->quality = 4;
ptr->image_size = 0;
ptr->scanning = SANE_FALSE;
+ ptr->overwrite_eop_pixel = SANE_TRUE;
+ ptr->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST;
+ ptr->eop_trailing_lines_color = 0x7f007f;
*handle = ptr;
@@ -542,29 +731,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
opts[HP5590_OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
opts[HP5590_OPT_MODE].constraint.string_list = mode_list;
- available_sources = 1; /* Flatbed is always available */
- if (ptr->info->features & FEATURE_ADF)
- available_sources += 2;
- if (ptr->info->features & FEATURE_TMA)
- available_sources += 2;
- available_sources++; /* Count terminating NULL */
- sources_list = malloc (available_sources * sizeof (SANE_String_Const));
- if (!sources_list)
- return SANE_STATUS_NO_MEM;
- source_idx = 0;
- sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_FLATBED;
- if (ptr->info->features & FEATURE_ADF)
- {
- sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_ADF;
- sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX;
- }
- if (ptr->info->features & FEATURE_TMA)
- {
- sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_TMA_SLIDES;
- sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES;
- }
- sources_list[source_idx] = NULL;
-
+ /* Show all features, check on feature in command line evaluation. */
opts[HP5590_OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE;
opts[HP5590_OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
opts[HP5590_OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
@@ -605,6 +772,46 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint_type = SANE_CONSTRAINT_NONE;
opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint.string_list = NULL;
+ opts[HP5590_OPT_BUTTON_PRESSED].name = SANE_NAME_BUTTON_PRESSED;
+ opts[HP5590_OPT_BUTTON_PRESSED].title = SANE_TITLE_BUTTON_PRESSED;
+ opts[HP5590_OPT_BUTTON_PRESSED].desc = SANE_DESC_BUTTON_PRESSED;
+ opts[HP5590_OPT_BUTTON_PRESSED].type = SANE_TYPE_STRING;
+ opts[HP5590_OPT_BUTTON_PRESSED].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_BUTTON_PRESSED].size = BUTTON_PRESSED_VALUE_MAX_KEY_LEN;
+ opts[HP5590_OPT_BUTTON_PRESSED].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
+ opts[HP5590_OPT_BUTTON_PRESSED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
+ opts[HP5590_OPT_BUTTON_PRESSED].constraint.string_list = buttonstate_list;
+
+ opts[HP5590_OPT_COLOR_LED].name = SANE_NAME_COLOR_LED;
+ opts[HP5590_OPT_COLOR_LED].title = SANE_TITLE_COLOR_LED;
+ opts[HP5590_OPT_COLOR_LED].desc = SANE_DESC_COLOR_LED;
+ opts[HP5590_OPT_COLOR_LED].type = SANE_TYPE_STRING;
+ opts[HP5590_OPT_COLOR_LED].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_COLOR_LED].size = COLOR_LED_VALUE_MAX_KEY_LEN;
+ opts[HP5590_OPT_COLOR_LED].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
+ opts[HP5590_OPT_COLOR_LED].constraint_type = SANE_CONSTRAINT_STRING_LIST;
+ opts[HP5590_OPT_COLOR_LED].constraint.string_list = colorledstate_list;
+
+ opts[HP5590_OPT_LCD_COUNTER].name = SANE_NAME_LCD_COUNTER;
+ opts[HP5590_OPT_LCD_COUNTER].title = SANE_TITLE_LCD_COUNTER;
+ opts[HP5590_OPT_LCD_COUNTER].desc = SANE_DESC_LCD_COUNTER;
+ opts[HP5590_OPT_LCD_COUNTER].type = SANE_TYPE_INT;
+ opts[HP5590_OPT_LCD_COUNTER].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_LCD_COUNTER].size = sizeof(SANE_Int);
+ opts[HP5590_OPT_LCD_COUNTER].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
+ opts[HP5590_OPT_LCD_COUNTER].constraint_type = SANE_CONSTRAINT_RANGE;
+ opts[HP5590_OPT_LCD_COUNTER].constraint.range = &lcd_counter_range;
+
+ opts[HP5590_OPT_DOC_IN_ADF].name = SANE_NAME_DOC_IN_ADF;
+ opts[HP5590_OPT_DOC_IN_ADF].title = SANE_TITLE_DOC_IN_ADF;
+ opts[HP5590_OPT_DOC_IN_ADF].desc = SANE_DESC_DOC_IN_ADF;
+ opts[HP5590_OPT_DOC_IN_ADF].type = SANE_TYPE_BOOL;
+ opts[HP5590_OPT_DOC_IN_ADF].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_DOC_IN_ADF].size = sizeof(SANE_Bool);
+ opts[HP5590_OPT_DOC_IN_ADF].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT;
+ opts[HP5590_OPT_DOC_IN_ADF].constraint_type = SANE_CONSTRAINT_NONE;
+ opts[HP5590_OPT_DOC_IN_ADF].constraint.range = NULL;
+
opts[HP5590_OPT_PREVIEW].name = SANE_NAME_PREVIEW;
opts[HP5590_OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
opts[HP5590_OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
@@ -615,6 +822,36 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle)
opts[HP5590_OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE;
opts[HP5590_OPT_PREVIEW].constraint.string_list = NULL;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].name = SANE_NAME_OVERWRITE_EOP_PIXEL;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].title = SANE_TITLE_OVERWRITE_EOP_PIXEL;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].desc = SANE_DESC_OVERWRITE_EOP_PIXEL;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].type = SANE_TYPE_BOOL;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].size = sizeof(SANE_Bool);
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint_type = SANE_CONSTRAINT_NONE;
+ opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint.string_list = NULL;
+
+ opts[HP5590_OPT_TRAILING_LINES_MODE].name = SANE_NAME_TRAILING_LINES_MODE;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].title = SANE_TITLE_TRAILING_LINES_MODE;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].desc = SANE_DESC_TRAILING_LINES_MODE;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].type = SANE_TYPE_STRING;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].size = TRAILING_LINES_MODE_MAX_KEY_LEN;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
+ opts[HP5590_OPT_TRAILING_LINES_MODE].constraint.string_list = trailingmode_list;
+
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].name = SANE_NAME_TRAILING_LINES_COLOR;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].title = SANE_TITLE_TRAILING_LINES_COLOR;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].desc = SANE_DESC_TRAILING_LINES_COLOR;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].type = SANE_TYPE_INT;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].unit = SANE_UNIT_NONE;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].size = sizeof(SANE_Int);
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint_type = SANE_CONSTRAINT_NONE;
+ opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint.string_list = NULL;
+
ptr->opts = opts;
return SANE_STATUS_GOOD;
@@ -646,285 +883,541 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
return &scanner->opts[option];
}
+/*************************************DS:Support function read buttons status */
+SANE_Status
+read_button_pressed(SANE_Handle handle, enum button_status * button_pressed)
+{
+ struct hp5590_scanner * scanner = handle;
+ *button_pressed = BUTTON_NONE;
+ enum button_status status = BUTTON_NONE;
+ DBG (DBG_verbose, "%s: Checking button status (device_number = %u) (device_name = %s)\n", __func__, scanner->dn, scanner->sane.name);
+ SANE_Status ret = hp5590_read_buttons (scanner->dn, scanner->proto_flags, &status);
+ if (ret != SANE_STATUS_GOOD)
+ {
+ DBG (DBG_proc, "%s: Error reading button status (%u)\n", __func__, ret);
+ return ret;
+ }
+ DBG (DBG_verbose, "%s: Button pressed = %d\n", __func__, status);
+ *button_pressed = status;
+ return SANE_STATUS_GOOD;
+}
+
+/******************************************************************************/
+SANE_Status
+read_lcd_and_led_values(SANE_Handle handle,
+ SANE_Int * lcd_counter,
+ enum color_led_status * color_led)
+{
+ struct hp5590_scanner * scanner = handle;
+ *lcd_counter = 1;
+ *color_led = LED_COLOR;
+ DBG (DBG_verbose, "%s: Reading LCD and LED values (device_number = %u) (device_name = %s)\n",
+ __func__, scanner->dn, scanner->sane.name);
+ SANE_Status ret = hp5590_read_lcd_and_led (scanner->dn, scanner->proto_flags, lcd_counter, color_led);
+ if (ret != SANE_STATUS_GOOD)
+ {
+ DBG (DBG_proc, "%s: Error reading LCD and LED values (%u)\n", __func__, ret);
+ return ret;
+ }
+ DBG (DBG_verbose, "%s: LCD = %d, LED = %s\n", __func__, *lcd_counter,
+ *color_led == LED_BLACKWHITE ? COLOR_LED_VALUE_BLACKWHITE_KEY : COLOR_LED_VALUE_COLOR_KEY);
+ return SANE_STATUS_GOOD;
+}
+
+/******************************************************************************/
+SANE_Status
+read_doc_in_adf_value(SANE_Handle handle,
+ SANE_Bool * doc_in_adf)
+{
+ struct hp5590_scanner * scanner = handle;
+ DBG (DBG_verbose, "%s: Reading state of document-available in ADF (device_number = %u) (device_name = %s)\n",
+ __func__, scanner->dn, scanner->sane.name);
+ SANE_Status ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags);
+ if (ret == SANE_STATUS_GOOD)
+ *doc_in_adf = SANE_TRUE;
+ else if (ret == SANE_STATUS_NO_DOCS)
+ *doc_in_adf = SANE_FALSE;
+ else
+ {
+ DBG (DBG_proc, "%s: Error reading state of document-available in ADF (%u)\n", __func__, ret);
+ return ret;
+ }
+ DBG (DBG_verbose, "%s: doc_in_adf = %s\n", __func__, *doc_in_adf == SANE_FALSE ? "false" : "true");
+ return SANE_STATUS_GOOD;
+}
+
/******************************************************************************/
SANE_Status
sane_control_option (SANE_Handle handle, SANE_Int option,
- SANE_Action action, void *value,
+ SANE_Action action, void *value,
SANE_Int * info)
{
- struct hp5590_scanner *scanner = handle;
-
+ struct hp5590_scanner *scanner = handle;
+
if (!value)
return SANE_STATUS_INVAL;
if (!handle)
return SANE_STATUS_INVAL;
-
+
if (option >= HP5590_OPT_LAST)
return SANE_STATUS_INVAL;
if (action == SANE_ACTION_GET_VALUE)
{
if (option == HP5590_OPT_NUM)
- {
- DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST);
- *((SANE_Int *) value) = HP5590_OPT_LAST;
- return SANE_STATUS_GOOD;
- }
-
+ {
+ DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST);
+ *((SANE_Int *) value) = HP5590_OPT_LAST;
+ return SANE_STATUS_GOOD;
+ }
+
if (!scanner->opts)
- return SANE_STATUS_INVAL;
-
+ return SANE_STATUS_INVAL;
+
DBG (DBG_proc, "%s: get option '%s' value\n", __func__, scanner->opts[option].name);
if (option == HP5590_OPT_BR_X)
- {
- *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4);
- }
+ {
+ *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4);
+ }
if (option == HP5590_OPT_BR_Y)
- {
- *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4);
- }
+ {
+ *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4);
+ }
if (option == HP5590_OPT_TL_X)
- {
- *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4);
- }
+ {
+ *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4);
+ }
if (option == HP5590_OPT_TL_Y)
- {
- *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4);
- }
+ {
+ *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4);
+ }
if (option == HP5590_OPT_MODE)
- {
- switch (scanner->depth) {
- case DEPTH_BW:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART));
- break;
- case DEPTH_GRAY:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY));
- break;
- case DEPTH_COLOR_24:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24));
- break;
- case DEPTH_COLOR_48:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48));
- break;
- default:
- return SANE_STATUS_INVAL;
- }
- }
+ {
+ switch (scanner->depth) {
+ case DEPTH_BW:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART));
+ break;
+ case DEPTH_GRAY:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY));
+ break;
+ case DEPTH_COLOR_24:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24));
+ break;
+ case DEPTH_COLOR_48:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48));
+ break;
+ default:
+ return SANE_STATUS_INVAL;
+ }
+ }
if (option == HP5590_OPT_SOURCE)
- {
- switch (scanner->source) {
- case SOURCE_FLATBED:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED));
- break;
- case SOURCE_ADF:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF));
- break;
- case SOURCE_ADF_DUPLEX:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX));
- break;
- case SOURCE_TMA_SLIDES:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES));
- break;
- case SOURCE_TMA_NEGATIVES:
- memset (value , 0, scanner->opts[option].size);
- memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES));
- break;
- case SOURCE_NONE:
- default:
- return SANE_STATUS_INVAL;
- }
- }
+ {
+ switch (scanner->source) {
+ case SOURCE_FLATBED:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED));
+ break;
+ case SOURCE_ADF:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF));
+ break;
+ case SOURCE_ADF_DUPLEX:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX));
+ break;
+ case SOURCE_TMA_SLIDES:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES));
+ break;
+ case SOURCE_TMA_NEGATIVES:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES));
+ break;
+ case SOURCE_NONE:
+ default:
+ return SANE_STATUS_INVAL;
+ }
+ }
if (option == HP5590_OPT_RESOLUTION)
- {
- *(SANE_Int *) value = scanner->dpi;
- }
+ {
+ *(SANE_Int *) value = scanner->dpi;
+ }
if (option == HP5590_OPT_LAMP_TIMEOUT)
- {
- *(SANE_Bool *) value = scanner->extend_lamp_timeout;
- }
+ {
+ *(SANE_Bool *) value = scanner->extend_lamp_timeout;
+ }
if (option == HP5590_OPT_WAIT_FOR_BUTTON)
- {
- *(SANE_Bool *) value = scanner->wait_for_button;
- }
+ {
+ *(SANE_Bool *) value = scanner->wait_for_button;
+ }
+
+ if (option == HP5590_OPT_BUTTON_PRESSED)
+ {
+ enum button_status button_pressed = BUTTON_NONE;
+ SANE_Status ret = read_button_pressed(scanner, &button_pressed);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+ switch (button_pressed) {
+ case BUTTON_POWER:
+ strncpy (value, BUTTON_PRESSED_VALUE_POWER_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_SCAN:
+ strncpy (value, BUTTON_PRESSED_VALUE_SCAN_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_COLLECT:
+ strncpy (value, BUTTON_PRESSED_VALUE_COLLECT_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_FILE:
+ strncpy (value, BUTTON_PRESSED_VALUE_FILE_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_EMAIL:
+ strncpy (value, BUTTON_PRESSED_VALUE_EMAIL_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_COPY:
+ strncpy (value, BUTTON_PRESSED_VALUE_COPY_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_UP:
+ strncpy (value, BUTTON_PRESSED_VALUE_UP_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_DOWN:
+ strncpy (value, BUTTON_PRESSED_VALUE_DOWN_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_MODE:
+ strncpy (value, BUTTON_PRESSED_VALUE_MODE_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_CANCEL:
+ strncpy (value, BUTTON_PRESSED_VALUE_CANCEL_KEY, scanner->opts[option].size);
+ break;
+ case BUTTON_NONE:
+ default:
+ strncpy (value, BUTTON_PRESSED_VALUE_NONE_KEY, scanner->opts[option].size);
+ }
+ }
+
+ if (option == HP5590_OPT_COLOR_LED)
+ {
+ SANE_Int lcd_counter = 0;
+ enum color_led_status color_led = LED_COLOR;
+ SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+ switch (color_led) {
+ case LED_BLACKWHITE:
+ strncpy (value, COLOR_LED_VALUE_BLACKWHITE_KEY, scanner->opts[option].size);
+ break;
+ case LED_COLOR:
+ default:
+ strncpy (value, COLOR_LED_VALUE_COLOR_KEY, scanner->opts[option].size);
+ }
+ }
+
+ if (option == HP5590_OPT_LCD_COUNTER)
+ {
+ SANE_Int lcd_counter = 0;
+ enum color_led_status color_led = LED_COLOR;
+ SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+ *(SANE_Int *) value = lcd_counter;
+ }
+
+ if (option == HP5590_OPT_DOC_IN_ADF)
+ {
+ SANE_Bool doc_in_adf = SANE_FALSE;
+ SANE_Status ret = read_doc_in_adf_value(scanner, &doc_in_adf);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+ *(SANE_Bool *) value = doc_in_adf;
+ }
if (option == HP5590_OPT_PREVIEW)
- {
- *(SANE_Bool *) value = scanner->preview;
- }
+ {
+ *(SANE_Bool *) value = scanner->preview;
+ }
+
+ if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL)
+ {
+ *(SANE_Bool *) value = scanner->overwrite_eop_pixel;
+ }
+
+ if (option == HP5590_OPT_TRAILING_LINES_MODE)
+ {
+ switch (scanner->eop_trailing_lines_mode) {
+ case TRAILING_LINES_MODE_RAW:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, TRAILING_LINES_MODE_RAW_KEY, strlen (TRAILING_LINES_MODE_RAW_KEY));
+ break;
+ case TRAILING_LINES_MODE_LAST:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, TRAILING_LINES_MODE_LAST_KEY, strlen (TRAILING_LINES_MODE_LAST_KEY));
+ break;
+ case TRAILING_LINES_MODE_RASTER:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, TRAILING_LINES_MODE_RASTER_KEY, strlen (TRAILING_LINES_MODE_RASTER_KEY));
+ break;
+ case TRAILING_LINES_MODE_BLACK:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, TRAILING_LINES_MODE_BLACK_KEY, strlen (TRAILING_LINES_MODE_BLACK_KEY));
+ break;
+ case TRAILING_LINES_MODE_WHITE:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, TRAILING_LINES_MODE_WHITE_KEY, strlen (TRAILING_LINES_MODE_WHITE_KEY));
+ break;
+ case TRAILING_LINES_MODE_COLOR:
+ memset (value , 0, scanner->opts[option].size);
+ memcpy (value, TRAILING_LINES_MODE_COLOR_KEY, strlen (TRAILING_LINES_MODE_COLOR_KEY));
+ break;
+ default:
+ return SANE_STATUS_INVAL;
+ }
+ }
+
+ if (option == HP5590_OPT_TRAILING_LINES_COLOR)
+ {
+ *(SANE_Int *) value = scanner->eop_trailing_lines_color;
+ }
}
-
+
if (action == SANE_ACTION_SET_VALUE)
{
if (option == HP5590_OPT_NUM)
- return SANE_STATUS_INVAL;
+ return SANE_STATUS_INVAL;
if (option == HP5590_OPT_BR_X)
- {
- float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
- if (val <= scanner->tl_x)
- return SANE_STATUS_GOOD;
- scanner->br_x = val;
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS;
- }
+ {
+ float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
+ if (val <= scanner->tl_x)
+ return SANE_STATUS_GOOD;
+ scanner->br_x = val;
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS;
+ }
if (option == HP5590_OPT_BR_Y)
- {
- float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
- if (val <= scanner->tl_y)
- return SANE_STATUS_GOOD;
- scanner->br_y = val;
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS;
- }
+ {
+ float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
+ if (val <= scanner->tl_y)
+ return SANE_STATUS_GOOD;
+ scanner->br_y = val;
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS;
+ }
if (option == HP5590_OPT_TL_X)
- {
- float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
- if (val >= scanner->br_x)
- return SANE_STATUS_GOOD;
- scanner->tl_x = val;
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS;
- }
+ {
+ float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
+ if (val >= scanner->br_x)
+ return SANE_STATUS_GOOD;
+ scanner->tl_x = val;
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS;
+ }
if (option == HP5590_OPT_TL_Y)
- {
- float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
- if (val >= scanner->br_y)
- return SANE_STATUS_GOOD;
- scanner->tl_y = val;
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS;
- }
+ {
+ float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4;
+ if (val >= scanner->br_y)
+ return SANE_STATUS_GOOD;
+ scanner->tl_y = val;
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS;
+ }
if (option == HP5590_OPT_MODE)
- {
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0)
- {
- scanner->depth = DEPTH_BW;
- }
-
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0)
- {
- scanner->depth = DEPTH_GRAY;
- }
-
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0)
- {
- scanner->depth = DEPTH_COLOR_24;
- }
-
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0)
- {
- scanner->depth = DEPTH_COLOR_48;
- }
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- }
+ {
+ if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0)
+ {
+ scanner->depth = DEPTH_BW;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0)
+ {
+ scanner->depth = DEPTH_GRAY;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0)
+ {
+ scanner->depth = DEPTH_COLOR_24;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0)
+ {
+ scanner->depth = DEPTH_COLOR_48;
+ }
+ else
+ {
+ return SANE_STATUS_INVAL;
+ }
+
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
+ }
if (option == HP5590_OPT_SOURCE)
- {
+ {
range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4);
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0)
- {
- scanner->source = SOURCE_FLATBED;
- range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
- range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4);
- scanner->br_x = scanner->info->max_size_x;
- scanner->br_y = scanner->info->max_size_y;
- }
- /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually
- * bigger than what scanner reports back during initialization
- */
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0)
- {
- scanner->source = SOURCE_ADF;
- range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
- range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4);
- scanner->br_x = scanner->info->max_size_x;
- scanner->br_y = ADF_MAX_Y_INCHES * 25.4;
- }
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0)
- {
- scanner->source = SOURCE_ADF_DUPLEX;
- range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
- range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4 * 2);
- scanner->br_y = ADF_MAX_Y_INCHES * 25.4 * 2;
- scanner->br_x = scanner->info->max_size_x;
- }
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0)
- {
- scanner->source = SOURCE_TMA_SLIDES;
- range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4);
- range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4);
- scanner->br_x = TMA_MAX_X_INCHES * 25.4;
- scanner->br_y = TMA_MAX_Y_INCHES * 25.4;
- }
- if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0)
- {
- scanner->source = SOURCE_TMA_NEGATIVES;
- range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4);
- range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4);
- scanner->br_x = TMA_MAX_X_INCHES * 25.4;
- scanner->br_y = TMA_MAX_Y_INCHES * 25.4;
- }
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
- }
+ if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0)
+ {
+ scanner->source = SOURCE_FLATBED;
+ range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
+ range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4);
+ scanner->br_x = scanner->info->max_size_x;
+ scanner->br_y = scanner->info->max_size_y;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0)
+ {
+ /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually
+ * bigger than what scanner reports back during initialization
+ */
+ if (! (scanner->info->features & FEATURE_ADF))
+ {
+ DBG(DBG_err, "ADF feature not available: %s\n", (char *) value);
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ scanner->source = SOURCE_ADF;
+ range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
+ range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4);
+ scanner->br_x = scanner->info->max_size_x;
+ scanner->br_y = ADF_MAX_Y_INCHES;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0)
+ {
+ if (! (scanner->info->features & FEATURE_ADF))
+ {
+ DBG(DBG_err, "ADF feature not available: %s\n", (char *) value);
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ scanner->source = SOURCE_ADF_DUPLEX;
+ range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4);
+ range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4);
+ scanner->br_x = scanner->info->max_size_x;
+ scanner->br_y = ADF_MAX_Y_INCHES;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0)
+ {
+ if (! (scanner->info->features & FEATURE_TMA))
+ {
+ DBG(DBG_err, "TMA feature not available: %s\n", (char *) value);
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ scanner->source = SOURCE_TMA_SLIDES;
+ range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4);
+ range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4);
+ scanner->br_x = TMA_MAX_X_INCHES;
+ scanner->br_y = TMA_MAX_Y_INCHES;
+ }
+ else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0)
+ {
+ if (! (scanner->info->features & FEATURE_TMA))
+ {
+ DBG(DBG_err, "TMA feature not available: %s\n", (char *) value);
+ return SANE_STATUS_UNSUPPORTED;
+ }
+ scanner->source = SOURCE_TMA_NEGATIVES;
+ range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4);
+ range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4);
+ scanner->br_x = TMA_MAX_X_INCHES;
+ scanner->br_y = TMA_MAX_Y_INCHES;
+ }
+ else
+ {
+ return SANE_STATUS_INVAL;
+ }
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
+ }
if (option == HP5590_OPT_RESOLUTION)
- {
- scanner->dpi = *(SANE_Int *) value;
- if (info)
- *info = SANE_INFO_RELOAD_PARAMS;
- }
+ {
+ scanner->dpi = *(SANE_Int *) value;
+ if (info)
+ *info = SANE_INFO_RELOAD_PARAMS;
+ }
if (option == HP5590_OPT_LAMP_TIMEOUT)
- {
- scanner->extend_lamp_timeout = *(SANE_Bool *) value;
- }
+ {
+ scanner->extend_lamp_timeout = *(SANE_Bool *) value;
+ }
if (option == HP5590_OPT_WAIT_FOR_BUTTON)
- {
- scanner->wait_for_button = *(SANE_Bool *) value;
- }
+ {
+ scanner->wait_for_button = *(SANE_Bool *) value;
+ }
+
+ if (option == HP5590_OPT_BUTTON_PRESSED)
+ {
+ DBG(DBG_verbose, "State of buttons is read only. Setting of state will be ignored.\n");
+ }
+
+ if (option == HP5590_OPT_COLOR_LED)
+ {
+ DBG(DBG_verbose, "State of color LED indicator is read only. Setting of state will be ignored.\n");
+ }
+
+ if (option == HP5590_OPT_LCD_COUNTER)
+ {
+ DBG(DBG_verbose, "Value of LCD counter is read only. Setting of value will be ignored.\n");
+ }
+
+ if (option == HP5590_OPT_DOC_IN_ADF)
+ {
+ DBG(DBG_verbose, "Value of document-available indicator is read only. Setting of value will be ignored.\n");
+ }
if (option == HP5590_OPT_PREVIEW)
- {
- scanner->preview = *(SANE_Bool *) value;
- }
+ {
+ scanner->preview = *(SANE_Bool *) value;
+ }
+
+ if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL)
+ {
+ scanner->overwrite_eop_pixel = *(SANE_Bool *) value;
+ }
+
+ if (option == HP5590_OPT_TRAILING_LINES_MODE)
+ {
+ if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RAW_KEY) == 0)
+ scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RAW;
+ if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_LAST_KEY) == 0)
+ scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST;
+ if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RASTER_KEY) == 0)
+ scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RASTER;
+ if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_BLACK_KEY) == 0)
+ scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_BLACK;
+ if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_WHITE_KEY) == 0)
+ scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_WHITE;
+ if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_COLOR_KEY) == 0)
+ scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_COLOR;
+ }
+
+ if (option == HP5590_OPT_TRAILING_LINES_COLOR)
+ {
+ scanner->eop_trailing_lines_color = *(SANE_Int *) value;
+ }
}
-
+
return SANE_STATUS_GOOD;
}
/******************************************************************************/
SANE_Status sane_get_parameters (SANE_Handle handle,
- SANE_Parameters * params)
+ SANE_Parameters * params)
{
- struct hp5590_scanner *scanner = handle;
- SANE_Status ret;
- unsigned int pixel_bits;
+ struct hp5590_scanner *scanner = handle;
+ SANE_Status ret;
+ unsigned int pixel_bits;
DBG (DBG_proc, "%s\n", __func__);
@@ -935,10 +1428,10 @@ SANE_Status sane_get_parameters (SANE_Handle handle,
return SANE_STATUS_INVAL;
ret = calc_image_params (scanner,
- (unsigned int *) &pixel_bits,
- (unsigned int *) &params->pixels_per_line,
- (unsigned int *) &params->bytes_per_line,
- (unsigned int *) &params->lines, NULL);
+ (unsigned int *) &pixel_bits,
+ (unsigned int *) &params->pixels_per_line,
+ (unsigned int *) &params->bytes_per_line,
+ (unsigned int *) &params->lines, NULL);
if (ret != SANE_STATUS_GOOD)
return ret;
@@ -964,11 +1457,11 @@ SANE_Status sane_get_parameters (SANE_Handle handle,
params->format = SANE_FRAME_RGB;
break;
default:
- DBG(0, "%s: Unknown depth\n", __func__);
+ DBG(DBG_err, "%s: Unknown depth\n", __func__);
return SANE_STATUS_INVAL;
}
-
+
DBG (DBG_proc, "format: %u, last_frame: %u, bytes_per_line: %u, "
"pixels_per_line: %u, lines: %u, depth: %u\n",
params->format, params->last_frame,
@@ -982,31 +1475,61 @@ SANE_Status sane_get_parameters (SANE_Handle handle,
SANE_Status
sane_start (SANE_Handle handle)
{
- struct hp5590_scanner *scanner = handle;
- SANE_Status ret;
- unsigned int bytes_per_line;
+ struct hp5590_scanner *scanner = handle;
+ SANE_Status ret;
+ unsigned int bytes_per_line;
DBG (DBG_proc, "%s\n", __func__);
if (!scanner)
return SANE_STATUS_INVAL;
+ /* Cleanup for all pages. */
+ if (scanner->eop_last_line_data)
+ {
+ /* Release last line data */
+ free (scanner->eop_last_line_data);
+ scanner->eop_last_line_data = NULL;
+ scanner->eop_last_line_data_rpos = 0;
+ }
+ if (scanner->one_line_read_buffer)
+ {
+ /* Release temporary line buffer. */
+ free (scanner->one_line_read_buffer);
+ scanner->one_line_read_buffer = NULL;
+ scanner->one_line_read_buffer_rpos = 0;
+ }
+ if (scanner->color_shift_line_buffer1)
+ {
+ /* Release line buffer1 for shifting colors. */
+ free (scanner->color_shift_line_buffer1);
+ scanner->color_shift_line_buffer1 = NULL;
+ scanner->color_shift_buffered_lines1 = 0;
+ }
+ if (scanner->color_shift_line_buffer2)
+ {
+ /* Release line buffer2 for shifting colors. */
+ free (scanner->color_shift_line_buffer2);
+ scanner->color_shift_line_buffer2 = NULL;
+ scanner->color_shift_buffered_lines2 = 0;
+ }
+
if ( scanner->scanning == SANE_TRUE
&& ( scanner->source == SOURCE_ADF
- || scanner->source == SOURCE_ADF_DUPLEX))
+ || scanner->source == SOURCE_ADF_DUPLEX))
{
DBG (DBG_verbose, "%s: Scanner is scanning, check if more data is available\n",
- __func__);
+ __func__);
ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags);
if (ret == SANE_STATUS_GOOD)
- {
- DBG (DBG_verbose, "%s: More data is available\n", __func__);
- scanner->transferred_image_size = scanner->image_size;
- return SANE_STATUS_GOOD;
- }
+ {
+ DBG (DBG_verbose, "%s: More data is available\n", __func__);
+ scanner->transferred_image_size = scanner->image_size;
+ return SANE_STATUS_GOOD;
+ }
if (ret != SANE_STATUS_NO_DOCS)
- return ret;
+ return ret;
}
sane_cancel (handle);
@@ -1015,25 +1538,25 @@ sane_start (SANE_Handle handle)
{
enum button_status status;
for (;;)
- {
- ret = hp5590_read_buttons (scanner->dn,
- scanner->proto_flags,
- &status);
- if (ret != SANE_STATUS_GOOD)
- return ret;
-
- if (status == BUTTON_CANCEL)
- return SANE_STATUS_CANCELLED;
-
- if (status != BUTTON_NONE && status != BUTTON_POWER)
- break;
- sleep (1);
- }
+ {
+ ret = hp5590_read_buttons (scanner->dn,
+ scanner->proto_flags,
+ &status);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+
+ if (status == BUTTON_CANCEL)
+ return SANE_STATUS_CANCELLED;
+
+ if (status != BUTTON_NONE && status != BUTTON_POWER)
+ break;
+ usleep (100 * 1000);
+ }
}
- DBG (DBG_verbose, "Init scanner\n");
+ DBG (DBG_verbose, "Init scanner\n");
ret = hp5590_init_scanner (scanner->dn, scanner->proto_flags,
- NULL, SCANNER_NONE);
+ NULL, SCANNER_NONE);
if (ret != SANE_STATUS_GOOD)
return ret;
@@ -1043,21 +1566,21 @@ sane_start (SANE_Handle handle)
DBG (DBG_verbose, "Wakeup\n");
ret = hp5590_select_source_and_wakeup (scanner->dn, scanner->proto_flags,
- scanner->source,
- scanner->extend_lamp_timeout);
+ scanner->source,
+ scanner->extend_lamp_timeout);
if (ret != SANE_STATUS_GOOD)
return ret;
-
+
ret = hp5590_set_scan_params (scanner->dn,
- scanner->proto_flags,
- scanner->info,
- scanner->tl_x * scanner->dpi,
- scanner->tl_y * scanner->dpi,
- (scanner->br_x - scanner->tl_x) * scanner->dpi,
- (scanner->br_y - scanner->tl_y) * scanner->dpi,
- scanner->dpi,
- scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL,
- scanner->source);
+ scanner->proto_flags,
+ scanner->info,
+ scanner->tl_x * scanner->dpi,
+ scanner->tl_y * scanner->dpi,
+ (scanner->br_x - scanner->tl_x) * scanner->dpi,
+ (scanner->br_y - scanner->tl_y) * scanner->dpi,
+ scanner->dpi,
+ scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL,
+ scanner->source);
if (ret != SANE_STATUS_GOOD)
{
hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
@@ -1065,8 +1588,8 @@ sane_start (SANE_Handle handle)
}
ret = calc_image_params (scanner, NULL, NULL,
- &bytes_per_line, NULL,
- &scanner->image_size);
+ &bytes_per_line, NULL,
+ &scanner->image_size);
if (ret != SANE_STATUS_GOOD)
{
hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
@@ -1079,35 +1602,35 @@ sane_start (SANE_Handle handle)
|| scanner->depth == DEPTH_COLOR_48)
{
DBG (1, "Color 24/48 bits: checking if image size is correctly "
- "aligned on number of colors\n");
+ "aligned on number of colors\n");
if (bytes_per_line % 3)
- {
- DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) "
- "(image size: %u, bytes per line %u)\n",
- scanner->image_size, bytes_per_line);
+ {
+ DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) "
+ "(image size: %llu, bytes per line %u)\n",
+ scanner->image_size, bytes_per_line);
hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
- return SANE_STATUS_INVAL;
- }
+ return SANE_STATUS_INVAL;
+ }
DBG (1, "Color 24/48 bits: image size is correctly aligned on number of colors "
- "(image size: %u, bytes per line %u)\n",
- scanner->image_size, bytes_per_line);
+ "(image size: %llu, bytes per line %u)\n",
+ scanner->image_size, bytes_per_line);
DBG (1, "Color 24/48 bits: checking if image size is correctly "
- "aligned on bytes per line\n");
+ "aligned on bytes per line\n");
if (scanner->image_size % bytes_per_line)
- {
- DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line "
- "(image size: %u, bytes per line %u)\n",
- scanner->image_size, bytes_per_line);
+ {
+ DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line "
+ "(image size: %llu, bytes per line %u)\n",
+ scanner->image_size, bytes_per_line);
hp5590_reset_scan_head (scanner->dn, scanner->proto_flags);
- return SANE_STATUS_INVAL;
- }
+ return SANE_STATUS_INVAL;
+ }
DBG (1, "Color 24/48 bits: image size correctly aligned on bytes per line "
- "(images size: %u, bytes per line: %u)\n",
- scanner->image_size, bytes_per_line);
+ "(images size: %llu, bytes per line: %u)\n",
+ scanner->image_size, bytes_per_line);
}
-
- DBG (DBG_verbose, "Final image size: %u\n", scanner->image_size);
+
+ DBG (DBG_verbose, "Final image size: %llu\n", scanner->image_size);
DBG (DBG_verbose, "Reverse calibration maps\n");
ret = hp5590_send_reverse_calibration_map (scanner->dn, scanner->proto_flags);
@@ -1125,14 +1648,23 @@ sane_start (SANE_Handle handle)
return ret;
}
+ if (scanner->adf_next_page_lines_data)
+ {
+ free (scanner->adf_next_page_lines_data);
+ scanner->adf_next_page_lines_data = NULL;
+ scanner->adf_next_page_lines_data_size = 0;
+ scanner->adf_next_page_lines_data_rpos = 0;
+ scanner->adf_next_page_lines_data_wpos = 0;
+ }
+
scanner->scanning = SANE_TRUE;
DBG (DBG_verbose, "Starting scan\n");
ret = hp5590_start_scan (scanner->dn, scanner->proto_flags);
/* Check for paper jam */
- if ( ret == SANE_STATUS_DEVICE_BUSY
+ if ( ret == SANE_STATUS_DEVICE_BUSY
&& ( scanner->source == SOURCE_ADF
- || scanner->source == SOURCE_ADF_DUPLEX))
+ || scanner->source == SOURCE_ADF_DUPLEX))
return SANE_STATUS_JAMMED;
if (ret != SANE_STATUS_GOOD)
@@ -1145,44 +1677,218 @@ sane_start (SANE_Handle handle)
}
/******************************************************************************/
-static SANE_Status
-convert_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)
+static void
+invert_negative_colors (unsigned char *buf, unsigned int bytes_per_line, struct hp5590_scanner *scanner)
{
- SANE_Int i;
+ /* Invert lineart or negatives. */
+ int is_linear = (scanner->depth == DEPTH_BW);
+ int is_negative = (scanner->source == SOURCE_TMA_NEGATIVES);
+ if (is_linear ^ is_negative)
+ {
+ for (unsigned int k = 0; k < bytes_per_line; k++)
+ buf[k] ^= 0xff;
+ }
+}
- DBG (DBG_proc, "%s\n", __func__);
+/******************************************************************************/
+static SANE_Status
+convert_gray_and_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)
+{
+ unsigned int pixels_per_line;
+ unsigned int pixel_bits;
+ unsigned int bytes_per_line;
+ unsigned int lines;
+ unsigned char *buf;
+ SANE_Status ret;
hp5590_assert (scanner != NULL);
hp5590_assert (data != NULL);
- /* Invert lineart */
- if (scanner->depth == DEPTH_BW)
+ if ( ! (scanner->depth == DEPTH_BW || scanner->depth == DEPTH_GRAY))
+ return SANE_STATUS_GOOD;
+
+ DBG (DBG_proc, "%s\n", __func__);
+
+ ret = calc_image_params (scanner,
+ &pixel_bits,
+ &pixels_per_line, &bytes_per_line,
+ NULL, NULL);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+
+ lines = size / bytes_per_line;
+
+ buf = data;
+ for (unsigned int i = 0; i < lines; buf += bytes_per_line, ++i)
{
- for (i = 0; i < size; i++)
- data[i] ^= 0xff;
+ if (! scanner->eop_last_line_data)
+ {
+ if (pixels_per_line > 0)
+ {
+ /* Test for last-line indicator pixel. If found, store last line
+ * and optionally overwrite indicator pixel with neighbor value.
+ */
+ unsigned int j = bytes_per_line - 1;
+ int eop_found = 0;
+ if (scanner->depth == DEPTH_GRAY)
+ {
+ eop_found = (buf[j] != 0);
+ if (scanner->overwrite_eop_pixel && (j > 0))
+ {
+ buf[j] = buf[j-1];
+ }
+ }
+ else if (scanner->depth == DEPTH_BW)
+ {
+ eop_found = (buf[j] != 0);
+ if (scanner->overwrite_eop_pixel && (j > 0))
+ {
+ buf[j] = (buf[j-1] & 0x01) ? 0xff : 0;
+ }
+ }
+
+ invert_negative_colors (buf, bytes_per_line, scanner);
+
+ if (eop_found && (! scanner->eop_last_line_data))
+ {
+ DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", i);
+ scanner->eop_last_line_data = malloc(bytes_per_line);
+ if (! scanner->eop_last_line_data)
+ return SANE_STATUS_NO_MEM;
+
+ memcpy (scanner->eop_last_line_data, buf, bytes_per_line);
+ scanner->eop_last_line_data_rpos = 0;
+
+ /* Fill trailing line buffer with requested color. */
+ if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER)
+ {
+ /* Black-white raster. */
+ if (scanner->depth == DEPTH_BW)
+ {
+ memset (scanner->eop_last_line_data, 0xaa, bytes_per_line);
+ }
+ else
+ {
+ /* Gray. */
+ for (unsigned int k = 0; k < bytes_per_line; ++k)
+ {
+ scanner->eop_last_line_data[k] = (k & 1 ? 0xff : 0);
+ }
+ }
+ }
+ else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE)
+ {
+ /* White. */
+ if (scanner->depth == DEPTH_BW)
+ {
+ memset (scanner->eop_last_line_data, 0x00, bytes_per_line);
+ }
+ else
+ {
+ memset (scanner->eop_last_line_data, 0xff, bytes_per_line);
+ }
+ }
+ else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK)
+ {
+ /* Black. */
+ if (scanner->depth == DEPTH_BW)
+ {
+ memset (scanner->eop_last_line_data, 0xff, bytes_per_line);
+ }
+ else
+ {
+ memset (scanner->eop_last_line_data, 0x00, bytes_per_line);
+ }
+ }
+ else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR)
+ {
+ if (scanner->depth == DEPTH_BW)
+ {
+ /* Black or white. */
+ memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0x01 ? 0x00 : 0xff, bytes_per_line);
+ }
+ else
+ {
+ /* Gray value */
+ memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0xff, bytes_per_line);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n",
+ i, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color);
+
+ if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX))
+ {
+ /* We are in in ADF mode after last-line and store next page data
+ * to buffer.
+ */
+ if (! scanner->adf_next_page_lines_data)
+ {
+ unsigned int n_rest_lines = lines - i;
+ unsigned int buf_size = n_rest_lines * bytes_per_line;
+ scanner->adf_next_page_lines_data = malloc(buf_size);
+ if (! scanner->adf_next_page_lines_data)
+ return SANE_STATUS_NO_MEM;
+ scanner->adf_next_page_lines_data_size = buf_size;
+ scanner->adf_next_page_lines_data_rpos = 0;
+ scanner->adf_next_page_lines_data_wpos = 0;
+ DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines);
+ }
+ DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", i, lines);
+ invert_negative_colors (buf, bytes_per_line, scanner);
+ memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line);
+ scanner->adf_next_page_lines_data_wpos += bytes_per_line;
+ }
+
+ if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW)
+ {
+ /* Copy last line data or corresponding color over trailing lines
+ * data.
+ */
+ memcpy (buf, scanner->eop_last_line_data, bytes_per_line);
+ }
+ }
}
return SANE_STATUS_GOOD;
}
/******************************************************************************/
+static unsigned char
+get_checked (unsigned char *ptr, unsigned int i, unsigned int length)
+{
+ if (i < length)
+ {
+ return ptr[i];
+ }
+ DBG (DBG_details, "get from array out of range: idx=%u, size=%u\n", i, length);
+ return 0;
+}
+
+/******************************************************************************/
static SANE_Status
convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)
{
unsigned int pixels_per_line;
+ unsigned int pixel_bits;
unsigned int bytes_per_color;
unsigned int bytes_per_line;
+ unsigned int bytes_per_line_limit;
unsigned int lines;
unsigned int i, j;
unsigned char *buf;
+ unsigned char *bufptr;
unsigned char *ptr;
- SANE_Status ret;
+ SANE_Status ret;
hp5590_assert (scanner != NULL);
hp5590_assert (data != NULL);
- if ( scanner->depth == DEPTH_BW
- || scanner->depth == DEPTH_GRAY)
+ if ( ! (scanner->depth == DEPTH_COLOR_24 || scanner->depth == DEPTH_COLOR_48))
return SANE_STATUS_GOOD;
DBG (DBG_proc, "%s\n", __func__);
@@ -1193,79 +1899,555 @@ convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size)
#endif
ret = calc_image_params (scanner,
- NULL,
- &pixels_per_line, &bytes_per_line,
- NULL, NULL);
+ &pixel_bits,
+ &pixels_per_line, &bytes_per_line,
+ NULL, NULL);
if (ret != SANE_STATUS_GOOD)
return ret;
lines = size / bytes_per_line;
- bytes_per_color = bytes_per_line / 3;
-
- DBG (DBG_verbose, "Length : %u\n", size);
+ bytes_per_color = (pixel_bits + 7) / 8;
+
+ bytes_per_line_limit = bytes_per_line;
+ if ((scanner->depth == DEPTH_COLOR_48) && (bytes_per_line_limit > 3))
+ {
+ /* Last-line indicator pixel has only 3 bytes instead of 6. */
+ bytes_per_line_limit -= 3;
+ }
+
+ DBG (DBG_verbose, "Length : %u\n", size);
DBG (DBG_verbose, "Converting row RGB to normal RGB\n");
DBG (DBG_verbose, "Bytes per line %u\n", bytes_per_line);
+ DBG (DBG_verbose, "Bytes per line limited %u\n", bytes_per_line_limit);
DBG (DBG_verbose, "Bytes per color %u\n", bytes_per_color);
+ DBG (DBG_verbose, "Pixels per line %u\n", pixels_per_line);
DBG (DBG_verbose, "Lines %u\n", lines);
- buf = malloc (bytes_per_line);
- if (!buf)
+ /* Use working buffer for color mapping. */
+ bufptr = malloc (size);
+ if (! bufptr)
return SANE_STATUS_NO_MEM;
+ memset (bufptr, 0, size);
+ buf = bufptr;
ptr = data;
- for (j = 0; j < lines; ptr += bytes_per_line, j++)
+ for (j = 0; j < lines; ptr += bytes_per_line_limit, buf += bytes_per_line, j++)
{
- memset (buf, 0, bytes_per_line);
for (i = 0; i < pixels_per_line; i++)
- {
- if (scanner->depth == DEPTH_COLOR_24)
- {
- /* R */
- buf[i*3] = ptr[i];
- /* G */
- buf[i*3+1] = ptr[i+bytes_per_color];
- /* B */
- buf[i*3+2] = ptr[i+bytes_per_color*2];
- }
- else
- {
- /* R */
- buf[i*6] = ptr[2*i+1];
- buf[i*6+1] = ptr[2*i];
- /* G */
- buf[i*6+2] = ptr[2*i+bytes_per_color+1];
- buf[i*6+3] = ptr[2*i+bytes_per_color];
- /* B */
- buf[i*6+4] = ptr[2*i+bytes_per_color*2+1];
- buf[i*6+5] = ptr[2*i+bytes_per_color*2];
- }
- }
-
- /* Invert pixels in case of TMA Negatives source has been selected */
- if (scanner->source == SOURCE_TMA_NEGATIVES)
{
- for (i = 0; i < bytes_per_line; i++)
- buf[i] ^= 0xff;
+ /* Color mapping from raw scanner data to RGB buffer. */
+ if (scanner->depth == DEPTH_COLOR_24)
+ {
+ /* R */
+ buf[i*3] = get_checked(ptr, i, bytes_per_line_limit);
+ /* G */
+ buf[i*3+1] = get_checked(ptr, i+pixels_per_line, bytes_per_line_limit);;
+ /* B */
+ buf[i*3+2] = get_checked(ptr, i+pixels_per_line*2, bytes_per_line_limit);
+ }
+ else if (scanner->depth == DEPTH_COLOR_48)
+ {
+ /* Note: The last-line indicator pixel uses only 24 bits, not 48.
+ *Blue uses offset of 2 bytes. Green swaps lo and hi.
+ */
+ /* R lo, hi*/
+ buf[i*6] = get_checked(ptr, 2*i+(pixels_per_line-1)*0+1, bytes_per_line_limit);
+ buf[i*6+1] = get_checked(ptr, 2*i+(pixels_per_line-1)*0+0, bytes_per_line_limit);
+ /* G lo, hi*/
+ buf[i*6+2] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+0, bytes_per_line_limit);
+ buf[i*6+3] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+1, bytes_per_line_limit);
+ /* B lo, hi*/
+ buf[i*6+4] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+1+2, bytes_per_line_limit);
+ buf[i*6+5] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+0+2, bytes_per_line_limit);
+ }
+ }
+
+ if (! scanner->eop_last_line_data)
+ {
+ if (pixels_per_line > 0)
+ {
+ /* Test for last-line indicator pixel on blue. If found, store
+ * last line and optionally overwrite indicator pixel with
+ * neighbor value.
+ */
+ i = pixels_per_line - 1;
+ int eop_found = 0;
+ if (scanner->depth == DEPTH_COLOR_24)
+ {
+ /* DBG (DBG_details, "BUF24: %u %u %u\n", buf[i*3], buf[i*3+1], buf[i*3+2]); */
+ eop_found = (buf[i*3+2] != 0);
+ if (scanner->overwrite_eop_pixel && (i > 0))
+ {
+ buf[i*3] = buf[(i-1)*3];
+ buf[i*3+1] = buf[(i-1)*3+1];
+ buf[i*3+2] = buf[(i-1)*3+2];
+ }
+ }
+ else if (scanner->depth == DEPTH_COLOR_48)
+ {
+ /* DBG (DBG_details, "BUF48: %u %u %u\n", buf[i*6+1], buf[i*6+3], buf[i*6+5]); */
+ eop_found = (buf[i*6+5] != 0);
+ if (scanner->overwrite_eop_pixel && (i > 0))
+ {
+ buf[i*6] = buf[(i-1)*6];
+ buf[i*6+1] = buf[(i-1)*6+1];
+ buf[i*6+2] = buf[(i-1)*6+2];
+ buf[i*6+3] = buf[(i-1)*6+3];
+ buf[i*6+4] = buf[(i-1)*6+4];
+ buf[i*6+5] = buf[(i-1)*6+5];
+ }
+ }
+
+ invert_negative_colors (buf, bytes_per_line, scanner);
+
+ if (eop_found && (! scanner->eop_last_line_data))
+ {
+ DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", j);
+ scanner->eop_last_line_data = malloc(bytes_per_line);
+ if (! scanner->eop_last_line_data)
+ return SANE_STATUS_NO_MEM;
+
+ memcpy (scanner->eop_last_line_data, buf, bytes_per_line);
+ scanner->eop_last_line_data_rpos = 0;
+
+ /* Fill trailing line buffer with requested color. */
+ if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER)
+ {
+ /* Black-white raster. */
+ if (scanner->depth == DEPTH_COLOR_24)
+ {
+ for (unsigned int k = 0; k < bytes_per_line; ++k)
+ {
+ scanner->eop_last_line_data[k] = (k % 6 < 3 ? 0xff : 0);
+ }
+ }
+ else
+ {
+ /* Color48. */
+ for (unsigned int k = 0; k < bytes_per_line; ++k)
+ {
+ scanner->eop_last_line_data[k] = (k % 12 < 6 ? 0xff : 0);
+ }
+ }
+ }
+ else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE)
+ {
+ memset (scanner->eop_last_line_data, 0xff, bytes_per_line);
+ }
+ else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK)
+ {
+ memset (scanner->eop_last_line_data, 0x00, bytes_per_line);
+ }
+ else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR)
+ {
+ /* RGB color value. */
+ int rgb[3];
+ rgb[0] = (scanner->eop_trailing_lines_color >> 16) & 0xff;
+ rgb[1] = (scanner->eop_trailing_lines_color >> 8) & 0xff;
+ rgb[2] = scanner->eop_trailing_lines_color & 0xff;
+ if (scanner->depth == DEPTH_COLOR_24)
+ {
+ for (unsigned int k = 0; k < bytes_per_line; ++k)
+ {
+ scanner->eop_last_line_data[k] = rgb[k % 3];
+ }
+ }
+ else
+ {
+ /* Color48. */
+ for (unsigned int k = 0; k < bytes_per_line; ++k)
+ {
+ scanner->eop_last_line_data[k] = rgb[(k % 6) >> 1];
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n",
+ j, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color);
+
+ if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX))
+ {
+ /* We are in in ADF mode after last-line and store next page data
+ * to buffer.
+ */
+ if (! scanner->adf_next_page_lines_data)
+ {
+ unsigned int n_rest_lines = lines - j;
+ unsigned int buf_size = n_rest_lines * bytes_per_line;
+ scanner->adf_next_page_lines_data = malloc(buf_size);
+ if (! scanner->adf_next_page_lines_data)
+ return SANE_STATUS_NO_MEM;
+ scanner->adf_next_page_lines_data_size = buf_size;
+ scanner->adf_next_page_lines_data_rpos = 0;
+ scanner->adf_next_page_lines_data_wpos = 0;
+ DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines);
+ }
+ DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", j, lines);
+ invert_negative_colors (buf, bytes_per_line, scanner);
+ memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line);
+ scanner->adf_next_page_lines_data_wpos += bytes_per_line;
+ }
+
+ if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW)
+ {
+ /* Copy last line data or corresponding color over trailing lines
+ * data.
+ */
+ memcpy (buf, scanner->eop_last_line_data, bytes_per_line);
+ }
+ }
+ }
+ memcpy (data, bufptr, size);
+ free (bufptr);
+
+ return SANE_STATUS_GOOD;
+}
+
+/******************************************************************************/
+static void
+read_data_from_temporary_buffer(struct hp5590_scanner *scanner,
+ SANE_Byte * data, unsigned int max_length,
+ unsigned int bytes_per_line, SANE_Int *length)
+{
+ *length = 0;
+ if (scanner && scanner->one_line_read_buffer)
+ {
+ /* Copy scan data from temporary read buffer and return size copied data. */
+ /* Release buffer, when no data left. */
+ unsigned int rest_len;
+ rest_len = bytes_per_line - scanner->one_line_read_buffer_rpos;
+ rest_len = (rest_len < max_length) ? rest_len : max_length;
+ if (rest_len > 0)
+ {
+ memcpy (data, scanner->one_line_read_buffer + scanner->one_line_read_buffer_rpos, rest_len);
+ scanner->one_line_read_buffer_rpos += rest_len;
+ scanner->transferred_image_size -= rest_len;
+ *length = rest_len;
+ }
+
+ DBG (DBG_verbose, "Copy scan data from temporary buffer: length = %u, rest in buffer = %u.\n",
+ *length, bytes_per_line - scanner->one_line_read_buffer_rpos);
+
+ if (scanner->one_line_read_buffer_rpos >= bytes_per_line)
+ {
+ DBG (DBG_verbose, "Release temporary buffer.\n");
+ free (scanner->one_line_read_buffer);
+ scanner->one_line_read_buffer = NULL;
+ scanner->one_line_read_buffer_rpos = 0;
+ }
+ }
+}
+
+/******************************************************************************/
+static SANE_Status
+sane_read_internal (struct hp5590_scanner * scanner, SANE_Byte * data,
+ SANE_Int max_length, SANE_Int * length, unsigned int bytes_per_line)
+{
+ SANE_Status ret;
+
+ DBG (DBG_proc, "%s, length %u, left %llu\n",
+ __func__,
+ max_length,
+ scanner->transferred_image_size);
+
+ SANE_Int length_limited = 0;
+ *length = max_length;
+ if ((unsigned long long) *length > scanner->transferred_image_size)
+ *length = (SANE_Int) scanner->transferred_image_size;
+
+ /* Align reading size to bytes per line. */
+ *length -= *length % bytes_per_line;
+
+ if (scanner->depth == DEPTH_COLOR_48)
+ {
+ /* Note: The last-line indicator pixel uses only 24 bits (3 bytes), not
+ * 48 bits (6 bytes).
+ */
+ if (bytes_per_line > 3)
+ {
+ length_limited = *length - *length % (bytes_per_line - 3);
+ }
+ }
+
+ DBG (DBG_verbose, "Aligning requested size to bytes per line "
+ "(requested: %d, aligned: %u, limit_for_48bit: %u)\n",
+ max_length, *length, length_limited);
+
+ if (max_length <= 0)
+ {
+ DBG (DBG_verbose, "Buffer too small for one scan line. Need at least %u bytes per line.\n",
+ bytes_per_line);
+ scanner->scanning = SANE_FALSE;
+ return SANE_STATUS_UNSUPPORTED;
+ }
+
+ if (scanner->one_line_read_buffer)
+ {
+ /* Copy scan data from temporary read buffer. */
+ read_data_from_temporary_buffer (scanner, data, max_length, bytes_per_line, length);
+ if (*length > 0)
+ {
+ DBG (DBG_verbose, "Return %d bytes, left %llu bytes.\n", *length, scanner->transferred_image_size);
+ return SANE_STATUS_GOOD;
+ }
+ }
+
+ /* Buffer to return scanned data. We need at least space for one line to
+ * simplify color processing and last-line detection. If call buffer is too
+ * small, use temporary read buffer for reading one line instead.
+ */
+ SANE_Byte * scan_data;
+ SANE_Int scan_data_length;
+ scan_data = data;
+ scan_data_length = *length;
+
+ /* Note, read length is shorter in 48bit mode. */
+ SANE_Int length_for_read = length_limited ? length_limited : scan_data_length;
+ if (length_for_read == 0)
+ {
+ /* Call buffer is too small for one line. Use temporary read buffer
+ * instead.
+ */
+ if (! scanner->one_line_read_buffer)
+ {
+ scanner->one_line_read_buffer = malloc (bytes_per_line);
+ if (! scanner->one_line_read_buffer)
+ return SANE_STATUS_NO_MEM;
+ memset (scanner->one_line_read_buffer, 0, bytes_per_line);
}
- memcpy (ptr, buf, bytes_per_line);
+ DBG (DBG_verbose, "Call buffer too small for one scan line. Use temporary read buffer for one line with %u bytes.\n",
+ bytes_per_line);
+
+ /* Scan and process next line in temporary buffer. */
+ scan_data = scanner->one_line_read_buffer;
+ scan_data_length = bytes_per_line;
+ length_for_read = bytes_per_line;
+ if (scanner->depth == DEPTH_COLOR_48)
+ {
+ /* The last-line indicator pixel uses only 24 bits (3 bytes), not 48
+ * bits (6 bytes).
+ */
+ if (length_for_read > 3)
+ {
+ length_for_read -= 3;
+ }
+ }
}
- free (buf);
+ int read_from_scanner = 1;
+ if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX))
+ {
+ if (scanner->eop_last_line_data)
+ {
+ /* Scanner is in ADF mode between last-line of previous page and
+ * start of next page.
+ * Fill remaining lines with last-line data.
+ */
+ unsigned int wpos = 0;
+ while (wpos < (unsigned int) scan_data_length)
+ {
+ unsigned int n1 = scan_data_length - wpos;
+ unsigned int n2 = bytes_per_line - scanner->eop_last_line_data_rpos;
+ n1 = (n1 < n2) ? n1 : n2;
+ memcpy (scan_data + wpos, scanner->eop_last_line_data + scanner->eop_last_line_data_rpos, n1);
+ wpos += n1;
+ scanner->eop_last_line_data_rpos += n1;
+ if (scanner->eop_last_line_data_rpos >= bytes_per_line)
+ scanner->eop_last_line_data_rpos = 0;
+ }
+ read_from_scanner = (wpos == 0);
+ DBG (DBG_verbose, "ADF use last-line data, wlength=%u, length=%u\n", wpos, scan_data_length);
+ }
+ else if (scanner->adf_next_page_lines_data)
+ {
+ /* Scanner is in ADF mode at start of next page and already some next
+ * page data is available from earlier read operation. Return this
+ * data.
+ */
+ unsigned int wpos = 0;
+ while ((wpos < (unsigned int) scan_data_length) &&
+ (scanner->adf_next_page_lines_data_rpos < scanner->adf_next_page_lines_data_size))
+ {
+ unsigned int n1 = scan_data_length - wpos;
+ unsigned int n2 = scanner->adf_next_page_lines_data_size - scanner->adf_next_page_lines_data_rpos;
+ n1 = (n1 < n2) ? n1 : n2;
+ memcpy (scan_data + wpos, scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_rpos, n1);
+ wpos += n1;
+ scanner->adf_next_page_lines_data_rpos += n1;
+ if (scanner->adf_next_page_lines_data_rpos >= scanner->adf_next_page_lines_data_size)
+ {
+ free (scanner->adf_next_page_lines_data);
+ scanner->adf_next_page_lines_data = NULL;
+ scanner->adf_next_page_lines_data_size = 0;
+ scanner->adf_next_page_lines_data_rpos = 0;
+ scanner->adf_next_page_lines_data_wpos = 0;
+ }
+ }
+ scan_data_length = wpos;
+ read_from_scanner = (wpos == 0);
+ DBG (DBG_verbose, "ADF use next-page data, wlength=%u, length=%u\n", wpos, scan_data_length);
+ }
+ }
+
+ if (read_from_scanner)
+ {
+ /* Read data from scanner. */
+ ret = hp5590_read (scanner->dn, scanner->proto_flags,
+ scan_data, length_for_read,
+ scanner->bulk_read_state);
+ if (ret != SANE_STATUS_GOOD)
+ {
+ scanner->scanning = SANE_FALSE;
+ return ret;
+ }
+
+ /* Look for last-line indicator pixels in convert functions.
+ * If found:
+ * - Overwrite indicator pixel with neighboring color (optional).
+ * - Save last line data for later use.
+ */
+ ret = convert_to_rgb (scanner, scan_data, scan_data_length);
+ if (ret != SANE_STATUS_GOOD)
+ {
+ scanner->scanning = SANE_FALSE;
+ return ret;
+ }
+
+ ret = convert_gray_and_lineart (scanner, scan_data, scan_data_length);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
+ }
+
+ if (data == scan_data)
+ {
+ /* Scanned to call buffer. */
+ scanner->transferred_image_size -= scan_data_length;
+ *length = scan_data_length;
+ }
+ else
+ {
+ /* Scanned to temporary read buffer. */
+ if (scanner->one_line_read_buffer)
+ {
+ /* Copy scan data from temporary read buffer. */
+ read_data_from_temporary_buffer (scanner, data, max_length, scan_data_length, length);
+ }
+ else
+ {
+ *length = 0;
+ }
+ }
+
+ DBG (DBG_verbose, "Return %d bytes, left %llu bytes\n", *length, scanner->transferred_image_size);
return SANE_STATUS_GOOD;
}
+/******************************************************************************
+ * Copy at maximum the last n lines from the src buffer to the begin of the dst
+ * buffer.
+ * Return number of lines copied.
+ */
+static SANE_Int
+copy_n_last_lines(SANE_Byte * src, SANE_Int src_len, SANE_Byte * dst, SANE_Int n, unsigned int bytes_per_line)
+{
+ DBG (DBG_proc, "%s\n", __func__);
+ SANE_Int n_copy = MY_MIN(src_len, n);
+ SANE_Byte * src1 = src + (src_len - n_copy) * bytes_per_line;
+ memcpy (dst, src1, n_copy * bytes_per_line);
+ return n_copy;
+}
+
+/******************************************************************************
+ * Copy the color values from line - delta_lines to line.
+ * buffer2 : Source and target buffer.
+ * buffer1 : Only source buffer. Contains lines scanned before lines in buffer1.
+ * color_idx : Index of color to be copied (0..2).
+ * delta_lines : color shift.
+ * color_48 : True = 2 byte , false = 1 byte per color.
+ */
+static void
+shift_color_lines(SANE_Byte * buffer2, SANE_Int n_lines2, SANE_Byte * buffer1, SANE_Int n_lines1, SANE_Int color_idx, SANE_Int delta_lines, SANE_Bool color_48, unsigned int bytes_per_line)
+{
+ DBG (DBG_proc, "%s\n", __func__);
+ for (SANE_Int i = n_lines2 - 1; i >= 0; --i) {
+ SANE_Byte * dst = buffer2 + i * bytes_per_line;
+ SANE_Int ii = i - delta_lines;
+ SANE_Byte * src = NULL;
+ SANE_Int source_color_idx = color_idx;
+ if (ii >= 0) {
+ /* Read from source and target buffer. */
+ src = buffer2 + ii * bytes_per_line;
+ } else {
+ ii += n_lines1;
+ if (ii >= 0) {
+ /* Read from source only buffer. */
+ src = buffer1 + ii * bytes_per_line;
+ } else {
+ /* Read other color from source position. */
+ src = dst;
+ source_color_idx = 2;
+ }
+ }
+ /* Copy selected color values. */
+ SANE_Int step = color_48 ? 2 : 1;
+ SANE_Int stride = 3 * step;
+ for (unsigned int pos = 0; pos < bytes_per_line; pos += stride) {
+ SANE_Int p1 = pos + step * source_color_idx;
+ SANE_Int p2 = pos + step * color_idx;
+ dst[p2] = src[p1];
+ if (color_48) {
+ dst[p2 + 1] = src[p1 + 1];
+ }
+ }
+ }
+}
+
+/******************************************************************************
+ * Append all lines from buffer2 to the end of buffer1 and keep max_lines last
+ * lines.
+ * buffer2 : Source line buffer.
+ * buffer1 : Target line buffer. Length will be adjusted.
+ * max_lines : Max number of lines in buffer1.
+ */
+static void
+append_and_move_lines(SANE_Byte * buffer2, SANE_Int n_lines2, SANE_Byte * buffer1, unsigned int * n_lines1_ptr, SANE_Int max_lines, unsigned int bytes_per_line)
+{
+ DBG (DBG_proc, "%s\n", __func__);
+ SANE_Int rest1 = max_lines - *n_lines1_ptr;
+ SANE_Int copy2 = MY_MIN(n_lines2, max_lines);
+ if (copy2 > rest1) {
+ SANE_Int shift1 = *n_lines1_ptr + copy2 - max_lines;
+ SANE_Int blen = MY_MIN(max_lines - shift1, (SANE_Int) *n_lines1_ptr);
+ SANE_Byte * pdst = buffer1;
+ SANE_Byte * psrc = pdst + shift1 * bytes_per_line;
+ for (SANE_Int i = 0; i < blen; ++i) {
+ memcpy (pdst, psrc, bytes_per_line);
+ pdst += bytes_per_line;
+ psrc += bytes_per_line;
+ }
+ *n_lines1_ptr -= shift1;
+ }
+ SANE_Int n_copied = copy_n_last_lines(buffer2, n_lines2, buffer1 + *n_lines1_ptr * bytes_per_line, copy2, bytes_per_line);
+ *n_lines1_ptr += n_copied;
+}
+
+
/******************************************************************************/
SANE_Status
sane_read (SANE_Handle handle, SANE_Byte * data,
- SANE_Int max_length, SANE_Int * length)
+ SANE_Int max_length, SANE_Int * length)
{
- struct hp5590_scanner *scanner = handle;
- SANE_Status ret;
+ struct hp5590_scanner *scanner = handle;
+ SANE_Status ret;
- DBG (DBG_proc, "%s, length %u, left %u\n",
+ DBG (DBG_proc, "%s, length %u, left %llu\n",
__func__,
max_length,
scanner->transferred_image_size);
@@ -1283,7 +2465,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data,
ret = hp5590_inc_scan_count (scanner->dn, scanner->proto_flags);
if (ret != SANE_STATUS_GOOD)
- return ret;
+ return ret;
/* Don't free bulk read state, some bytes could be left
* for the next images from ADF
@@ -1295,70 +2477,78 @@ sane_read (SANE_Handle handle, SANE_Byte * data,
{
ret = hp5590_low_init_bulk_read_state (&scanner->bulk_read_state);
if (ret != SANE_STATUS_GOOD)
- {
- scanner->scanning = SANE_FALSE;
- return ret;
- }
+ {
+ scanner->scanning = SANE_FALSE;
+ return ret;
+ }
}
- *length = max_length;
- if (*length > scanner->transferred_image_size)
- *length = scanner->transferred_image_size;
-
- if ( scanner->depth == DEPTH_COLOR_24
- || scanner->depth == DEPTH_COLOR_48)
- {
- unsigned int bytes_per_line;
- ret = calc_image_params (scanner,
- NULL, NULL,
- &bytes_per_line,
- NULL, NULL);
- if (ret != SANE_STATUS_GOOD)
- return ret;
+ unsigned int bytes_per_line;
+ ret = calc_image_params (scanner,
+ NULL, NULL,
+ &bytes_per_line,
+ NULL, NULL);
+ if (ret != SANE_STATUS_GOOD)
+ return ret;
- *length -= *length % bytes_per_line;
- DBG (2, "Aligning requested size to bytes per line "
- "(requested: %u, aligned: %u)\n",
- max_length, *length);
- }
+ ret = sane_read_internal(scanner, data, max_length, length, bytes_per_line);
- ret = hp5590_read (scanner->dn, scanner->proto_flags,
- data, *length, scanner->bulk_read_state);
- if (ret != SANE_STATUS_GOOD)
+ if ((ret == SANE_STATUS_GOOD) && (scanner->dpi == 2400) &&
+ ((scanner->depth == DEPTH_COLOR_48) || (scanner->depth == DEPTH_COLOR_24)))
{
- scanner->scanning = SANE_FALSE;
- return ret;
- }
+ /* Correct color shift bug for 2400 dpi.
+ * Note: 2400 dpi only works in color mode. Grey mode and lineart seem to
+ * fail.
+ * Align colors by shifting B channel by 48 lines and G channel by 24
+ * lines.
+ */
+ const SANE_Int offset_max = 48;
+ const SANE_Int offset_part = 24;
+ SANE_Bool color_48 = (scanner->depth == DEPTH_COLOR_48);
- scanner->transferred_image_size -= *length;
+ if (! scanner->color_shift_line_buffer1)
+ {
+ scanner->color_shift_buffered_lines1 = 0;
+ scanner->color_shift_line_buffer1 = malloc (bytes_per_line * offset_max);
+ if (! scanner->color_shift_line_buffer1)
+ return SANE_STATUS_NO_MEM;
+ memset (scanner->color_shift_line_buffer1, 0, bytes_per_line * offset_max);
+ }
+ if (! scanner->color_shift_line_buffer2)
+ {
+ scanner->color_shift_buffered_lines2 = 0;
+ scanner->color_shift_line_buffer2 = malloc (bytes_per_line * offset_max);
+ if (! scanner->color_shift_line_buffer2)
+ return SANE_STATUS_NO_MEM;
+ memset (scanner->color_shift_line_buffer2, 0, bytes_per_line * offset_max);
+ }
- ret = convert_to_rgb (scanner, data, *length);
- if (ret != SANE_STATUS_GOOD)
- {
- scanner->scanning = SANE_FALSE;
- return ret;
- }
+ SANE_Int n_lines = *length / bytes_per_line;
+ scanner->color_shift_buffered_lines2 = MY_MIN(n_lines, offset_max);
+ copy_n_last_lines(data, n_lines, scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, bytes_per_line);
- ret = convert_lineart (scanner, data, *length);
- if (ret != SANE_STATUS_GOOD)
- return ret;
+ shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 1, offset_part, color_48, bytes_per_line);
+ shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 0, offset_max, color_48, bytes_per_line);
- return SANE_STATUS_GOOD;
+ append_and_move_lines(scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, scanner->color_shift_line_buffer1, &(scanner->color_shift_buffered_lines1), offset_max, bytes_per_line);
+ }
+
+ return ret;
}
/******************************************************************************/
void
sane_cancel (SANE_Handle handle)
{
- struct hp5590_scanner *scanner = handle;
- SANE_Status ret;
+ struct hp5590_scanner *scanner = handle;
+ SANE_Status ret;
DBG (DBG_proc, "%s\n", __func__);
scanner->scanning = SANE_FALSE;
if (scanner->dn < 0)
- return;
+ return;
hp5590_low_free_bulk_read_state (&scanner->bulk_read_state);
@@ -1371,7 +2561,7 @@ sane_cancel (SANE_Handle handle)
SANE_Status
sane_set_io_mode (SANE_Handle __sane_unused__ handle,
- SANE_Bool __sane_unused__ non_blocking)
+ SANE_Bool __sane_unused__ non_blocking)
{
DBG (DBG_proc, "%s\n", __func__);
@@ -1381,7 +2571,7 @@ sane_set_io_mode (SANE_Handle __sane_unused__ handle,
/******************************************************************************/
SANE_Status
sane_get_select_fd (SANE_Handle __sane_unused__ handle,
- SANE_Int __sane_unused__ * fd)
+ SANE_Int __sane_unused__ * fd)
{
DBG (DBG_proc, "%s\n", __func__);