-- v11: sane.ds: Improve color mode and paper source detection
From: Ilia Docin ilya.docin@contentai.ru
--- dlls/sane.ds/capability.c | 154 +++++++++++++++++++++++++------------- dlls/sane.ds/options.c | 39 ++++++---- dlls/sane.ds/sane_i.h | 2 +- 3 files changed, 126 insertions(+), 69 deletions(-)
diff --git a/dlls/sane.ds/capability.c b/dlls/sane.ds/capability.c index 555575c45a4..bbe518c8513 100644 --- a/dlls/sane.ds/capability.c +++ b/dlls/sane.ds/capability.c @@ -277,47 +277,32 @@ static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action return twCC; }
-static TW_UINT16 set_color_mode(TW_UINT32 pixeltype) +static TW_UINT16 set_option_value(const char* option_name, char* option_value) { - TW_UINT16 twCC = TWCC_BADCAP; + TW_UINT16 twCC = TWCC_BADVALUE; BOOL reload = FALSE; - int i; - const char * const * modes; - /* most of the values are taken from https://gitlab.gnome.org/GNOME/simple-scan/-/blob/master/src/scanner.vala */ - static const char * const gray[] = {"Gray", "Grayscale", "True Gray", "8-bit Grayscale", "Grayscale - 256 Levels", "gray", - 0}; - static const char * const rgb[] = {"Color", "24bit Color[Fast]", "24bit Color", - "24 bit Color", "Color - 16 Million Colors", 0}; - static const char * const bw[] = {"Lineart", "LineArt", "Black & White", "Binary", "Thresholded", "1-bit Black & White", - "Black and White - Line Art", "Black and White - Halftone", "Monochrome", 0}; - switch (pixeltype) + if (*option_value) { - case TWPT_GRAY: - modes = gray; - break; - case TWPT_RGB: - modes = rgb; - break; - case TWPT_BW: - modes = bw; - break; - default: - ERR("Unsupported pixeltype %lu\n", pixeltype); - return TWCC_BADVALUE; - break; - } - TRACE("Setting pixeltype to %lu\n", pixeltype); - for(i=0; modes[i]; ++i) - { - twCC = sane_option_set_str("mode", (char*)modes[i], &reload); + twCC = sane_option_set_str(option_name, option_value, &reload); if (twCC == TWCC_SUCCESS) { if (reload) get_sane_params(&activeDS.frame_params); - break; } } return twCC; }
+static TW_UINT16 find_value_pos(const char* value, const char* values, TW_UINT16 buf_len, TW_UINT16 buf_count) +{ + TW_UINT16 index; + for (index=0; index<buf_count; ++index) + { + if (!strncmp(value, values, buf_len)) + return index; + values += buf_len; + } + return buf_count; +} + /* ICAP_PIXELTYPE */ static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action) { @@ -326,16 +311,39 @@ static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 actio int possible_value_count; TW_UINT32 val; TW_UINT16 current_pixeltype = TWPT_BW; + enum { buf_len = 64, buf_count = 3 }; + char color_modes[buf_len * buf_count] = {'\0'}, current_mode[buf_len] = {'\0'}, *output = 0; + /* most of the values are taken from https://gitlab.gnome.org/GNOME/simple-scan/-/blob/master/src/scanner.vala */ + static const WCHAR* bw[] = {L"Lineart", L"LineArt", L"Black & White", L"Binary", L"Thresholded", + L"1-bit Black & White", L"Black and White - Line Art", L"Black and White - Halftone", L"Monochrome", L"bw", 0}; + static const WCHAR* gray[] = {L"Gray", L"Grayscale", L"True Gray", L"8-bit Grayscale", L"Grayscale - 256 Levels", + L"gray", 0}; + static const WCHAR* rgb[] = {L"Color", L"24bit Color[Fast]", L"24bit Color", L"24 bit Color", + L"Color - 16 Million Colors", L"color", 0}; + static const WCHAR* const* filter[] = {bw, gray, rgb, 0};
TRACE("ICAP_PIXELTYPE\n"); + twCC = sane_option_probe_str("mode", filter, color_modes, buf_len); + if (twCC != TWCC_SUCCESS) + { + ERR("Unable to retrieve modes from sane, ICAP_PIXELTYPE unsupported\n"); + return twCC; + }
- twCC = sane_option_probe_mode(¤t_pixeltype, possible_values, &possible_value_count); + twCC = sane_option_get_str("mode", current_mode, buf_len); if (twCC != TWCC_SUCCESS) { - ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n"); + ERR("Unable to retrieve current mode from sane, ICAP_PIXELTYPE unsupported\n"); return twCC; }
+ current_pixeltype = find_value_pos(current_mode, color_modes, buf_len, buf_count); + if (current_pixeltype == buf_count) + { + ERR("Wrong current mode value, ICAP_PIXELTYPE unsupported\n"); + twCC = TWCC_BADVALUE; + return twCC; + } /* Sane does not support a concept of a default mode, so we simply cache * the first mode we find */ if (! activeDS.PixelTypeSet) @@ -352,17 +360,28 @@ static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 actio break;
case MSG_GET: + possible_value_count = 0; + for (val=TWPT_BW; val<=TWPT_RGB; ++val) + { + if (*(color_modes + val * buf_len)) + possible_values[possible_value_count++] = val; + } twCC = msg_get_enum(pCapability, possible_values, possible_value_count, TWTY_UINT16, current_pixeltype, activeDS.defaultPixelType); break;
case MSG_SET: twCC = msg_set(pCapability, &val); - if (twCC == TWCC_SUCCESS) + if ((twCC == TWCC_SUCCESS) && (val < buf_count)) { - TRACE("Setting pixeltype to %ld\n", val); - twCC = set_color_mode(val); + output = color_modes + val * buf_len; + TRACE("Setting pixeltype to %lu: %s\n", val, output); + twCC = set_option_value("mode", output); + if (twCC != TWCC_SUCCESS) + ERR("Unable to set pixeltype to %lu: %s\n", val, output); } + else + twCC = TWCC_BADVALUE; break;
case MSG_GETDEFAULT: @@ -370,7 +389,7 @@ static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 actio break;
case MSG_RESET: - twCC = set_color_mode(activeDS.defaultPixelType); + twCC = set_option_value("mode", color_modes + activeDS.defaultPixelType * buf_len); if (twCC == TWCC_SUCCESS) current_pixeltype = activeDS.defaultPixelType; else @@ -933,17 +952,39 @@ static TW_UINT16 SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability, TW_UINT16 ac TW_UINT16 twCC = TWCC_BADCAP; TW_UINT32 val; TW_BOOL enabled; - char source[64]; + enum { buf_len = 64, buf_count = 2 }; + char paper_sources[buf_len * buf_count] = {'\0'}, current_source[buf_len] = {'\0'}, *output = 0; + /* most of the values are taken from https://gitlab.gnome.org/GNOME/simple-scan/-/blob/master/src/scanner.vala */ + static const WCHAR* flatbed[] = {L"Flatbed", L"FlatBed", L"Platen", L"Normal", L"Document Table", 0}; + static const WCHAR* autofeeder[] = {L"Auto", L"ADF", L"ADF Front", L"ADF Back", L"adf", + L"Automatic Document Feeder", L"Automatic Document Feeder(centrally aligned)", + L"Automatic Document Feeder(center aligned)", L"Automatic Document Feeder(left aligned)", + L"ADF Simplex" L"DP", 0}; + static const WCHAR* const* filter[] = {flatbed, autofeeder, 0};
TRACE("CAP_FEEDERENABLED\n"); + twCC = sane_option_probe_str("source", filter, paper_sources, buf_len); + if (twCC != TWCC_SUCCESS) + { + ERR("Unable to retrieve paper sources from sane, CAP_FEEDERENABLED unsupported\n"); + return twCC; + }
- if (sane_option_get_str("source", source, sizeof(source)) != TWCC_SUCCESS) - return TWCC_BADCAP; + twCC = sane_option_get_str("source", current_source, buf_len); + if (twCC != TWCC_SUCCESS) + { + ERR("Unable to retrieve current paper source from sane, CAP_FEEDERENABLED unsupported\n"); + return twCC; + }
- if (strcmp(source, "Auto") == 0 || strcmp(source, "ADF") == 0) - enabled = TRUE; - else - enabled = FALSE; + val = find_value_pos(current_source, paper_sources, buf_len, buf_count); + if (val == buf_count) + { + ERR("Wrong current paper source value, CAP_FEEDERENABLED unsupported\n"); + twCC = TWCC_BADVALUE; + return twCC; + } + enabled = val > 0;
switch (action) { @@ -958,16 +999,16 @@ static TW_UINT16 SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability, TW_UINT16 ac
case MSG_SET: twCC = msg_set(pCapability, &val); - if (twCC == TWCC_SUCCESS) + if ((twCC == TWCC_SUCCESS) && (val < buf_count)) { - strcpy(source, "ADF"); - twCC = sane_option_set_str("source", source, NULL); + output = paper_sources + val * buf_len; + TRACE("Setting paper source to %lu: %s\n", val, output); + twCC = set_option_value("source", output); if (twCC != TWCC_SUCCESS) - { - strcpy(source, "Auto"); - twCC = sane_option_set_str("source", source, NULL); - } + ERR("Unable to set paper source to %lu: %s\n", val, output); } + else + twCC = TWCC_BADVALUE; break;
case MSG_GETDEFAULT: @@ -975,9 +1016,14 @@ static TW_UINT16 SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability, TW_UINT16 ac break;
case MSG_RESET: - strcpy(source, "Auto"); - if (sane_option_set_str("source", source, NULL) == TWCC_SUCCESS) - enabled = TRUE; + val = *(paper_sources + buf_len) ? 1 : 0; // set to Auto/ADF if it's supported + output = paper_sources + val * buf_len; + TRACE("Resetting paper source to %lu: %s\n", val, output); + twCC = set_option_value("source", output); + if (twCC != TWCC_SUCCESS) + ERR("Unable to reset paper source to %lu: %s\n", val, output); + else + enabled = val > 0; /* .. fall through intentional .. */
case MSG_GETCURRENT: diff --git a/dlls/sane.ds/options.c b/dlls/sane.ds/options.c index 1d39844a770..fd80efb4145 100644 --- a/dlls/sane.ds/options.c +++ b/dlls/sane.ds/options.c @@ -112,30 +112,41 @@ TW_UINT16 sane_option_probe_resolution(const char *option_name, struct option_de return sane_find_option(option_name, TYPE_INT, opt); }
-TW_UINT16 sane_option_probe_mode(TW_UINT16 *current, TW_UINT32 *choices, int *count) +static TW_UINT32 sane_categorize_value(const WCHAR* value, const WCHAR* const* filter[], char* categories, int buf_len) +{ + TW_UINT32 i, j; + for(i=0; filter[i]; ++i) + { + if (!*categories) + { + for(j=0; filter[i][j]; ++j) + { + if (!wcscmp(value, filter[i][j])) + { + wcstombs(categories, value, buf_len); + return i; + } + } + } + categories += buf_len; + } + return 0; +} + +TW_UINT16 sane_option_probe_str(const char* option_name, const WCHAR* const* filter[], char* opt_values, int buf_len) { WCHAR *p; - char buffer[256]; struct option_descriptor opt; - TW_UINT16 rc = sane_find_option("mode", TYPE_STRING, &opt); + TW_UINT16 rc = sane_find_option(option_name, TYPE_STRING, &opt);
if (rc != TWCC_SUCCESS) return rc; - if (opt.size > sizeof(buffer)) return TWCC_BADVALUE; - rc = sane_option_get_value( opt.optno, buffer ); - if (rc != TWCC_SUCCESS) return rc; - - if (!strcmp( buffer, "Lineart" )) *current = TWPT_BW; - else if (!strcmp( buffer, "Color" )) *current = TWPT_RGB; - else if (!strncmp( buffer, "Gray", 4 )) *current = TWPT_GRAY; + if (opt.size > buf_len) return TWCC_BADVALUE;
- *count = 0; if (opt.constraint_type == CONSTRAINT_STRING_LIST) { for (p = opt.constraint.strings; *p; p += lstrlenW(p) + 1) { - if (!wcscmp( p, L"Lineart" )) choices[(*count)++] = TWPT_BW; - else if (!wcscmp( p, L"Color" )) choices[(*count)++] = TWPT_RGB; - else if (!wcsncmp( p, L"Gray", 4 )) choices[(*count)++] = TWPT_GRAY; + sane_categorize_value(p, filter, opt_values, buf_len); } } return rc; diff --git a/dlls/sane.ds/sane_i.h b/dlls/sane.ds/sane_i.h index 47c5d69c82e..e35ed77c935 100644 --- a/dlls/sane.ds/sane_i.h +++ b/dlls/sane.ds/sane_i.h @@ -201,7 +201,7 @@ TW_UINT16 sane_option_set_int( const char *option_name, int val, BOOL *reload ); TW_UINT16 sane_option_get_str( const char *option_name, char *val, int len ); TW_UINT16 sane_option_set_str( const char *option_name, char *val, BOOL *reload ); TW_UINT16 sane_option_probe_resolution( const char *option_name, struct option_descriptor *opt ); -TW_UINT16 sane_option_probe_mode(TW_UINT16 *current, TW_UINT32 *choices, int *count); +TW_UINT16 sane_option_probe_str( const char* option_name, const WCHAR* const* filter[], char* opt_vals, int buf_len ); TW_UINT16 sane_option_get_bool( const char *option_name, BOOL *val ); TW_UINT16 sane_option_set_bool( const char *option_name, BOOL val ); TW_UINT16 sane_option_get_scan_area( int *tlx, int *tly, int *brx, int *bry );
On Mon Jun 24 17:06:32 2024 +0000, Esme Povirk wrote:
If I understand correctly (and there's a lot here that I could be confused about), we're supposed to return the value that this was set to, and this will return `enabled` which is the previous value. So I think we should set `enabled = val` if setting the option succeeds.
Oh, I see. Done.