In Twain the capability ICAP_BITDEPTH defines the number of bits to transfer per pixel during a scan. So for an RGB image with 8 bit per color channel, ICAP_BITDEPTH is 24.
In Sane the depth is defined as the number of bits per color channel, so for an RGB image with 8 bit per color channel, depth is 8.
See Page 10-132 (PDF Page 550) if the Twain 2.5 Spec. Obviously older spec versions where not as exact, so there were misunderstandings.
The existing code to handle ICAP_BITDEPTH did not consider this difference and returned the sane depth value.
This merge request fixes this and adds the ability to set the depth to 16 bit per color channel for those sane backends that support the "depth" option.
From: Bernd Herd codeberg@herdsoft.com
Twain ICAP_BITDEPTH is defined in bits per pixel, whereas in sane depth is defined per color channel. Fix it.
Also allows setting ICAP_BITDEPTH for those sane backends that allow it --- dlls/sane.ds/capability.c | 78 ++++++++++++++++++++++++++++++++++----- dlls/sane.ds/options.c | 2 +- dlls/sane.ds/sane_i.h | 1 + 3 files changed, 71 insertions(+), 10 deletions(-)
diff --git a/dlls/sane.ds/capability.c b/dlls/sane.ds/capability.c index 33b586b0824..52633931007 100644 --- a/dlls/sane.ds/capability.c +++ b/dlls/sane.ds/capability.c @@ -85,10 +85,10 @@ static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *value pCapability->hContainer = 0;
if (type == TWTY_INT16 || type == TWTY_UINT16) - pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)])); + pCapability->hContainer = GlobalAlloc (GMEM_ZEROINIT, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
if (type == TWTY_INT32 || type == TWTY_UINT32) - pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)])); + pCapability->hContainer = GlobalAlloc (GMEM_ZEROINIT, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
if (pCapability->hContainer) enumv = GlobalLock(pCapability->hContainer); @@ -476,30 +476,90 @@ static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action) static TW_UINT16 SANE_ICAPBitDepth(pTW_CAPABILITY pCapability, TW_UINT16 action) { TW_UINT16 twCC = TWCC_BADCAP; - TW_UINT32 possible_values[1]; + TW_UINT32 val; + TW_UINT32 sane_depth, twain_depth; + BOOL have_option_depth; + int samples_per_pixel; + struct option_descriptor opt;
TRACE("ICAP_BITDEPTH\n");
- possible_values[0] = activeDS.frame_params.depth; + get_sane_params(&activeDS.frame_params); // Updates activeDS.frame_params.format + samples_per_pixel=(activeDS.frame_params.format == FMT_RGB) ? 3 : 1; + + sane_depth=activeDS.frame_params.depth; + have_option_depth = + sane_find_option( "depth", TYPE_INT, &opt ) == TWCC_SUCCESS + && (opt.size==sizeof(TW_UINT32)); + if (have_option_depth) + { + twCC = sane_option_get_value(opt.optno, &sane_depth); + } + twain_depth = sane_depth*samples_per_pixel;
switch (action) { case MSG_QUERYSUPPORT: twCC = set_onevalue(pCapability, TWTY_INT32, - TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT ); + TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT | (have_option_depth ? TWQC_SET : 0) ); break;
case MSG_GET: - twCC = msg_get_enum(pCapability, possible_values, ARRAY_SIZE(possible_values), - TWTY_UINT16, activeDS.frame_params.depth, activeDS.frame_params.depth); + if (have_option_depth && + opt.constraint_type == CONSTRAINT_WORD_LIST && + opt.constraint.word_list[0]<=32) + { + /* The constraint word ist is in bits per color channel, for TWAIN we need bits per pixel */ + TW_UINT32 enum_bitdepths[32]; + int i; + for (i=0; i<opt.constraint.word_list[0]; i++) + enum_bitdepths[i] = opt.constraint.word_list[i+1] * samples_per_pixel; + twCC = msg_get_enum(pCapability, enum_bitdepths, opt.constraint.word_list[0], + TWTY_UINT16, twain_depth, twain_depth); + } + else + { + twCC = msg_get_enum(pCapability, &twain_depth, 1, + TWTY_UINT16, twain_depth, twain_depth); + } + break; + + case MSG_SET: + if (have_option_depth) + { + twCC = msg_set(pCapability, &val); + if (twCC == TWCC_SUCCESS) + { + BOOL reload = FALSE; + TW_UINT16 val16 = (TW_UINT16) val; + + /* TWAIN Spec 2.4 says unambiguous that the depth is defined per pixel, + * not per color channel. However it also warns that there have been + * misunderstandings. So interpret it... */ + if (val16==8 && samples_per_pixel==3) + { + val16=24; + } else if (val16==16 && samples_per_pixel==3) + { + val16=48; + } + sane_depth = val16/samples_per_pixel; + twCC = sane_option_set_value(opt.optno, &sane_depth, &reload); + if (reload) twCC = TWCC_CHECKSTATUS; + } + } + else + { + twCC = TWCC_BADCAP; + } break;
case MSG_GETDEFAULT: /* .. Fall through intentional .. */
case MSG_GETCURRENT: - TRACE("Returning current bitdepth of %d\n", activeDS.frame_params.depth); - twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.frame_params.depth); + TRACE("Returning current bitdepth of %ld\n", twain_depth); + twCC = set_onevalue(pCapability, TWTY_UINT16, twain_depth); break; } return twCC; diff --git a/dlls/sane.ds/options.c b/dlls/sane.ds/options.c index 335e0306f38..f46ba0f8fc7 100644 --- a/dlls/sane.ds/options.c +++ b/dlls/sane.ds/options.c @@ -40,7 +40,7 @@ TW_UINT16 sane_option_set_value( int optno, void *val, BOOL *reload ) return SANE_CALL( option_set_value, ¶ms ); }
-static TW_UINT16 sane_find_option( const char *name, int type, struct option_descriptor *descr ) +TW_UINT16 sane_find_option( const char *name, int type, struct option_descriptor *descr ) { struct option_find_descriptor_params params = { name, type, descr }; return SANE_CALL( option_find_descriptor, ¶ms ) ? TWCC_CAPUNSUPPORTED : TWCC_SUCCESS; diff --git a/dlls/sane.ds/sane_i.h b/dlls/sane.ds/sane_i.h index 0691f02e22d..4ce7f42e1b1 100644 --- a/dlls/sane.ds/sane_i.h +++ b/dlls/sane.ds/sane_i.h @@ -207,6 +207,7 @@ BOOL DoScannerUI(void); HWND ScanningDialogBox(HWND dialog, LONG progress);
/* Option functions */ +TW_UINT16 sane_find_option( const char *name, int type, struct option_descriptor *descr ); TW_UINT16 sane_option_get_value( int optno, void *val ); TW_UINT16 sane_option_set_value( int optno, void *val, BOOL *reload ); TW_UINT16 sane_option_get_int( const char *option_name, int *val );