Some kodak values for use with its SDMI flow.

This commit is contained in:
Eugene Wang
2025-02-18 15:24:55 -05:00
parent e3dfa8f4dd
commit 62eaa6083a
6 changed files with 1671 additions and 1498 deletions

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<!--change these in each release-->
<VersionPrefix>4.0.0.0</VersionPrefix>
<VersionSuffix>alpha.6</VersionSuffix>
<VersionSuffix>alpha.7</VersionSuffix>
<!--keep it the same until major # changes-->
<AssemblyVersion>4.0.0.0</AssemblyVersion>

View File

@@ -3989,7 +3989,12 @@ namespace NTwain.Data
RESETALL = 0x0A01,
// used with DAT_TWAINDIRECT
SETTASK = 0x0B01
SETTASK = 0x0B01,
/// <summary>
/// KODAK only. Used with DAT_EXTIMAGEINFO in state 6.
/// </summary>
GETSPECIAL = 0x8005
}
#endregion
@@ -4301,7 +4306,80 @@ namespace NTwain.Data
IAFIELDE_VALUE = 0x1250,
IALEVEL = 0x1251,
PRINTER = 0x1252,
BARCODETEXT2 = 0x1253
BARCODETEXT2 = 0x1253,
// KODAK USE
HDR_PAGESIDE = 0x8001, // 0-front 1-rear
HDR_DOCUMENTCOUNT = 0x8002, // Count of pages (seeded by user)
HDR_LENGTH = 0x8003, // Number of bytes of image data
HDR_LEVEL = 0x8004, // Image Address Level
HDR_MODE = 0x8005, // Gemini Mode (1-18)
HDR_LINELENGTH = 0x8006, // Width
HDR_PAGELENGTH = 0x8007, // Height
HDR_COMPRESSION = 0x8008, // ICAP_COMPRESSION TWCP_* value
HDR_DATE = 0x8009, // YY/MM/DD
HDR_TIME = 0x800A, // HH/MM/00
HDR_ROLL = 0x800B, // Imagelink 990 Film Roll Number
HDR_RESOLUTION = 0x800C, // Dots Per Inch (DPI)
HDR_BITORDER = 0x800D, // Bit order in a byte
HDR_SKEW = 0x800E, // (obsolete)
HDR_MOMENTARYFLAG = 0x800F, // Gemini Momentary
HDR_LATCHEDFLAG = 0x8010, // Gemini Latched
HDR_BARCODE = 0x8011, // Gemini Barcode(s)
HDR_DESKEW = 0x8012, // Deskew status
HDR_DESKEWANGLE = 0x8013, // Deskew angle
HDR_POLARITY = 0x8014, // ICAP_PIXELFLAVOR TWPF_* value
HDR_PRINTERSTRING = 0x8015, // Viper/Prism/Wildfire printed string
HDR_PRINTERINDEX = 0x8016, // Kinda like the document count
HDR_IMAGENUMBER = 0x8017, // Count images this session
HDR_PAGENUMBER = 0x8018, // Count sheets of paper this session
HDR_PAGEIMAGENUMBER = 0x8019, // Image count on a page (1 - 4)
HDR_BOOKNAME_A = 0x801A, // Fixed field Gemini/Prism/Wildfire A
HDR_BOOKNAME_B = 0x801B, // Fixed field Prism/Wildfire B
HDR_BOOKNAME_C = 0x801C, // Fixed field Prism/Wildfire C
HDR_BOOKNAME_D = 0x801D, // Fixed field Prism/Wildfire D
HDR_IMAGEADDRESSSTRING = 0x801E, // Prism/Wildfire image address string
HDR_XOFFSET = 0x801F, // Left cropping offset
HDR_YOFFSET = 0x8020, // Right cropping offset
HDR_FEATUREPATCH = 0x8021, // Feature patch (only image with patch: i200/i600)
HDR_IMAGEADDRESSDEFS = 0x8022, // Image Address field definitions
HDR_PCARD_HEADER = 0x8023, // Personality-Card Header
HDR_PCARD_FOOTER = 0x8024, // Personality-Card Footer
HDR_TOKEN_COUNT = 0x8025, // Alien token flag
HDR_REGENERATION = 0x8026, // Alien retry count
HDR_IMAGESTATUS = 0x8027, // Alien image status
HDR_DITHER = 0x8028, // Bitonal dithering algorithm used
HDR_PATCHDETECTED = 0x8029, // Patch was found on the document
HDR_FOLDEDCORNERPERCENTAGE = 0x802A, // Phoenix folded corner percentage
HDR_DESKEWCONFIDENCEFACTOR = 0x802B, // Phoenix deskew confidence factor
HDR_BITONALCONTRASTPERCENTAGE = 0x802C, // Phoenix bitonal contrast percentage
HDR_BITONALCONTRAST = 0x802D, // Phoenix bitonal contrast
HDR_BITONALTHRESHOLD = 0x802E, // Phoenix bitonal threshold
HDR_SUMHISTOGRAM = 0x802F, // Phoenix sum historgram
HDR_DIFFERENCEHISTOGRAM = 0x8030, // Phoenix difference histogram
HDR_GAMMATABLE = 0x8031, // Phoenix gamma table
HDR_MULTIFEED = 0x8032, // Multifeed detected
HDR_DESKEWANGLEACTUAL = 0x8033, // Signed deskew angle to scanner precision
HDR_RAWIMAGEHEADER = 0x8034, // Raw image header from scanner
HDR_LONGPAPERSEGMENT = 0x8035, // Long paper segment number
HDR_LONGPAPERLASTSEGMENT = 0x8036, // Long pager last segment
HDR_AUTOCOLORDETECTED = 0x8037, // Auto color detected
HDR_AUTOCOLORAMOUNT = 0x8038, // Auto color amount
HDR_AUTOCOLORTHRESHOLD = 0x8039, // Auto color threshold
HDR_XML = 0x803A, // <reportimage> data in XML format (see sample at end of file)
HDR_DROPOUTSTATUS = 0x803B, // ECDO Algorithm Status
HDR_PROCESSINGSTATUS = 0x803C, // Processing Status
HDR_BINARIZATIONQUALITY = 0x803D, // Conveys the quality level of the binarized image
HDR_DUALSTACKINGSTACK = 0x803E, // Which output tray a document was dropped into (i5000 only)
// Only valid if dual stacking is enabled; legal values are 1 and 2
HDR_PAPERDESTINATION = 0x803F, // Which output tray a document
// was dropped into (i5000 only)
HDR_SLEEVETYPE = 0x8040, // Type of sleeve that was detected during Sleeve Scanning
HDR_MULTIIMAGEINDEX = 0x8041, // Image ID for the image that was split from a document
HDR_MULTIIMAGETOTAL = 0x8042, // Total number of images split from a document
HDR_ENDOFSHEET = 0x8043, // Is this the last image on this sheet? (0-no or 1-yes)
HDR_STAMPEDSTRING = 0x8044, // Stamped string
HDR_STAMPCOUNT = 0x8045, // Digital Stamping Counter
}
public enum TWEJ : ushort
@@ -4387,7 +4465,20 @@ namespace NTwain.Data
GETCURRENT = 0x0008,
RESET = 0x0010,
SETCONSTRAINT = 0x0020,
CONSTRAINABLE = 0x0040
CONSTRAINABLE = 0x0040,
// KODAK additions
/// <summary>
/// KODAK ONLY: applies to entire session/machine
/// </summary>
MACHINE = 0x1000,
/// <summary>
/// KODAK ONLY: applies to Bitonal "cameras"
/// </summary>
BITONAL = 0x2000,
/// <summary>
/// KODAK ONLY: applies to Color "cameras"
/// </summary>
COLOR = 0x3000
}
/// <summary>

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +1,86 @@
using NTwain.Data;
using NTwain.DSM;
namespace NTwain.Triplets.ImageDATs
namespace NTwain.Triplets.ImageDATs;
/// <summary>
/// Contains calls used with <see cref="DG.IMAGE"/> and <see cref="DAT.EXTIMAGEINFO"/>.
/// </summary>
public class ExtImageInfo
{
/// <summary>
/// Contains calls used with <see cref="DG.IMAGE"/> and <see cref="DAT.EXTIMAGEINFO"/>.
/// </summary>
public class ExtImageInfo
{
/// <summary>
/// For use with all scanners in state 7.
/// </summary>
/// <param name="app"></param>
/// <param name="ds"></param>
/// <param name="data"></param>
/// <returns></returns>
public TWRC Get(ref TW_IDENTITY_LEGACY app, ref TW_IDENTITY_LEGACY ds, ref TW_EXTIMAGEINFO data)
{
var rc = TWRC.FAILURE;
if (TWPlatform.IsWindows)
{
if (TWPlatform.Is32bit && TWPlatform.PreferLegacyDSM)
var rc = TWRC.FAILURE;
if (TWPlatform.IsWindows)
{
rc = WinLegacyDSM.DSM_Entry(ref app, ref ds, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
if (TWPlatform.Is32bit && TWPlatform.PreferLegacyDSM)
{
rc = WinLegacyDSM.DSM_Entry(ref app, ref ds, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
}
else
{
rc = WinNewDSM.DSM_Entry(ref app, ref ds, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
}
}
else
else if (TWPlatform.IsMacOSX)
{
rc = WinNewDSM.DSM_Entry(ref app, ref ds, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
TW_IDENTITY_MACOSX app2 = app;
TW_IDENTITY_MACOSX ds2 = ds;
if (TWPlatform.PreferLegacyDSM)
{
rc = OSXLegacyDSM.DSM_Entry(ref app2, ref ds2, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
}
else
{
rc = OSXNewDSM.DSM_Entry(ref app2, ref ds2, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
}
}
}
else if (TWPlatform.IsMacOSX)
{
TW_IDENTITY_MACOSX app2 = app;
TW_IDENTITY_MACOSX ds2 = ds;
if (TWPlatform.PreferLegacyDSM)
{
rc = OSXLegacyDSM.DSM_Entry(ref app2, ref ds2, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
}
else
{
rc = OSXNewDSM.DSM_Entry(ref app2, ref ds2, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GET, ref data);
}
}
return rc;
return rc;
}
}
/// <summary>
/// For use with KODAK scanners in state 6.
/// </summary>
/// <param name="app"></param>
/// <param name="ds"></param>
/// <param name="data"></param>
/// <returns></returns>
public TWRC GetSpecial(ref TW_IDENTITY_LEGACY app, ref TW_IDENTITY_LEGACY ds, ref TW_EXTIMAGEINFO data)
{
var rc = TWRC.FAILURE;
if (TWPlatform.IsWindows)
{
if (TWPlatform.Is32bit && TWPlatform.PreferLegacyDSM)
{
rc = WinLegacyDSM.DSM_Entry(ref app, ref ds, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GETSPECIAL, ref data);
}
else
{
rc = WinNewDSM.DSM_Entry(ref app, ref ds, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GETSPECIAL, ref data);
}
}
else if (TWPlatform.IsMacOSX)
{
TW_IDENTITY_MACOSX app2 = app;
TW_IDENTITY_MACOSX ds2 = ds;
if (TWPlatform.PreferLegacyDSM)
{
rc = OSXLegacyDSM.DSM_Entry(ref app2, ref ds2, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GETSPECIAL, ref data);
}
else
{
rc = OSXNewDSM.DSM_Entry(ref app2, ref ds2, DG.IMAGE, DAT.EXTIMAGEINFO, MSG.GETSPECIAL, ref data);
}
}
return rc;
}
}

View File

@@ -1,6 +1,7 @@
using NTwain.Caps;
using NTwain.Data;
using NTwain.Triplets;
using NTwain.Triplets.ControlDATs;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -8,395 +9,394 @@ using System.Text;
namespace NTwain
{
// this file contains capability mgmt methods
// this file contains capability mgmt methods
partial class TwainAppSession
{
private KnownCaps? _knownCaps;
/// <summary>
/// Access the known and pre-defined caps as properties.
/// </summary>
public KnownCaps Caps
partial class TwainAppSession
{
get { return _knownCaps ??= new KnownCaps(this); }
}
private KnownCaps? _knownCaps;
/// <summary>
/// Gets a CAP's actual supported operations.
/// This is not supported by all sources.
/// </summary>
/// <param name="cap"></param>
/// <returns></returns>
public TWQC QueryCapSupport(CAP cap)
{
var value = new TW_CAPABILITY(cap) { ConType = TWON.ONEVALUE };
if (DGControl.Capability.QuerySupport(ref _appIdentity, ref _currentDS, ref value) == TWRC.SUCCESS)
{
return value.ReadOneValue<TWQC>(this);
}
return TWQC.Unknown;
}
/// <summary>
/// Gets a CAP's raw current value.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapCurrent(CAP cap, out TW_CAPABILITY value)
{
value = new TW_CAPABILITY(cap);
return WrapInSTS(DGControl.Capability.GetCurrent(ref _appIdentity, ref _currentDS, ref value));
}
/// <summary>
/// Gets a CAP's current value. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapCurrent<TValue>(CAP cap, out List<TValue> value) where TValue : struct
{
value = new List<TValue>();
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
/// <summary>
/// Access the known and pre-defined caps as properties.
/// </summary>
public KnownCaps Caps
{
case TWON.ONEVALUE:
value.Add(twcap.ReadOneValue<TValue>(this));
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
get { return _knownCaps ??= new KnownCaps(this); }
}
/// <summary>
/// Gets a CAP's actual supported operations.
/// This is not supported by all sources.
/// </summary>
/// <param name="cap"></param>
/// <returns></returns>
public TWQC QueryCapSupport(CAP cap)
{
var value = new TW_CAPABILITY(cap) { ConType = TWON.ONEVALUE };
if (DGControl.Capability.QuerySupport(ref _appIdentity, ref _currentDS, ref value) == TWRC.SUCCESS)
{
value.Add(twenum.Items[twenum.CurrentIndex]);
return value.ReadOneValue<TWQC>(this);
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
break;
default:
twcap.Free(this); break;
return TWQC.Unknown;
}
}
return sts;
}
/// <summary>
/// Gets a CAP's raw default value.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapDefault(CAP cap, out TW_CAPABILITY value)
{
value = new TW_CAPABILITY(cap);
return WrapInSTS(DGControl.Capability.GetDefault(ref _appIdentity, ref _currentDS, ref value));
}
/// <summary>
/// Gets a CAP's default value. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapDefault<TValue>(CAP cap, out List<TValue> value) where TValue : struct
{
value = new List<TValue>();
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
/// <summary>
/// Gets a CAP's raw current value.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapCurrent(CAP cap, out TW_CAPABILITY value)
{
case TWON.ONEVALUE:
value.Add(twcap.ReadOneValue<TValue>(this));
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.DefaultIndex < twenum.Items.Length)
value = new TW_CAPABILITY(cap);
return WrapInSTS(DGControl.Capability.GetCurrent(ref _appIdentity, ref _currentDS, ref value));
}
/// <summary>
/// Gets a CAP's current value. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapCurrent<TValue>(CAP cap, out List<TValue> value) where TValue : struct
{
value = new List<TValue>();
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
value.Add(twenum.Items[twenum.DefaultIndex]);
switch (twcap.ConType)
{
case TWON.ONEVALUE:
value.Add(twcap.ReadOneValue<TValue>(this));
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
{
value.Add(twenum.Items[twenum.CurrentIndex]);
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
break;
default:
twcap.Free(this); break;
}
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).DefaultValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
break;
default:
twcap.Free(this); break;
return sts;
}
}
return sts;
}
/// <summary>
/// Gets a CAP's raw supported values.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapValues(CAP cap, out TW_CAPABILITY value)
{
value = new TW_CAPABILITY(cap);
return WrapInSTS(DGControl.Capability.Get(ref _appIdentity, ref _currentDS, ref value));
}
/// <summary>
/// Gets a CAP's supported values. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="values"></param>
/// <returns></returns>
public STS GetCapValues<TValue>(CAP cap, out IList<TValue> values) where TValue : struct
{
values = new List<TValue>();
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
/// <summary>
/// Gets a CAP's raw default value.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapDefault(CAP cap, out TW_CAPABILITY value)
{
case TWON.ONEVALUE:
values.Add(twcap.ReadOneValue<TValue>(this));
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.Items.Length > 0)
((List<TValue>)values).AddRange(twenum.Items);
break;
case TWON.RANGE:
// This can be slow
var twrange = twcap.ReadRange<TValue>(this);
((List<TValue>)values).AddRange(twrange);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0)
((List<TValue>)values).AddRange(twarr);
break;
default:
twcap.Free(this); break;
value = new TW_CAPABILITY(cap);
return WrapInSTS(DGControl.Capability.GetDefault(ref _appIdentity, ref _currentDS, ref value));
}
}
return sts;
}
/// <summary>
/// Gets a CAP's help text (description).
/// This may not work due to unclear spec.
/// </summary>
/// <param name="cap"></param>
/// <param name="help"></param>
/// <returns></returns>
public STS GetCapHelp(CAP cap, out string? help)
{
help = null;
var value = new TW_CAPABILITY(cap);
var rc = DGControl.Capability.GetHelp(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
help = value.ReadString(this, false);
}
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Gets a CAP's text name label.
/// This may not work due to unclear spec.
/// </summary>
/// <param name="cap"></param>
/// <param name="label"></param>
/// <returns></returns>
public STS GetCapLabel(CAP cap, out string? label)
{
label = null;
var value = new TW_CAPABILITY(cap) { ConType = TWON.ONEVALUE };
var rc = DGControl.Capability.GetLabel(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
label = value.ReadString(this, false);
}
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Gets a CAP's enum/array value label texts.
/// </summary>
/// <param name="cap"></param>
/// <param name="labels"></param>
/// <returns></returns>
public STS GetCapLabelEnum(CAP cap, out IList<string> labels)
{
labels = Array.Empty<string>();
var value = new TW_CAPABILITY(cap);
var rc = DGControl.Capability.GetLabelEnum(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
// spec says they're utf8
labels = value.ReadArray<TW_STR255>(this, false).Select(t => t.Get(Encoding.UTF8)).ToList();
}
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Sets a CAP's current value.
/// An easy way to create a value is to use the
/// <see cref="ValueWriter.CreateOneValueCap{TValue}(CAP, IMemoryManager, TValue)"/>
/// extension method (or the other container variants).
/// Memory of the value will be freed afterwards.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public STS SetCap(ref TW_CAPABILITY value)
{
var rc = DGControl.Capability.Set(ref _appIdentity, ref _currentDS, ref value);
value.Free(this);
if (value.Cap == CAP.CAP_LANGUAGE && rc == TWRC.SUCCESS)
{
RefreshCapLanguage();
}
return WrapInSTS(rc);
}
/// <summary>
/// A simpler cap value setter for common one-value scenarios
/// that's easier to use. Not for other container type sets.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS SetCap<TValue>(CAP cap, TValue value) where TValue : struct
{
var twcap = ValueWriter.CreateOneValueCap(cap, this, value);
return SetCap(ref twcap);
}
/// <summary>
/// Sets a CAP's constraint values.
/// An easy way to create a value is to use the
/// <see cref="ValueWriter.CreateOneValueCap{TValue}(CAP, IMemoryManager, TValue)"/>
/// extension method (or the other container variants).
/// Memory of the value will be freed afterwards.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public STS SetConstraint(ref TW_CAPABILITY value)
{
var rc = DGControl.Capability.SetConstraint(ref _appIdentity, ref _currentDS, ref value);
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Resets a CAP's current value to power-on default.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS ResetCap(CAP cap, out TW_CAPABILITY value)
{
value = new TW_CAPABILITY(cap);
var rc = DGControl.Capability.Reset(ref _appIdentity, ref _currentDS, ref value);
if (value.Cap == CAP.CAP_LANGUAGE && rc == TWRC.SUCCESS)
{
RefreshCapLanguage();
}
return WrapInSTS(rc);
}
/// <summary>
/// Resets a CAP's current value to power-on default.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS ResetCap<TValue>(CAP cap, out TValue value) where TValue : struct
{
value = default;
var sts = ResetCap(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
/// <summary>
/// Gets a CAP's default value. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapDefault<TValue>(CAP cap, out List<TValue> value) where TValue : struct
{
case TWON.ONEVALUE:
value = twcap.ReadOneValue<TValue>(this);
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
value = new List<TValue>();
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
value = twenum.Items[twenum.CurrentIndex];
switch (twcap.ConType)
{
case TWON.ONEVALUE:
value.Add(twcap.ReadOneValue<TValue>(this));
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.DefaultIndex < twenum.Items.Length)
{
value.Add(twenum.Items[twenum.DefaultIndex]);
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRange<TValue>(this).DefaultValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <summary>
/// Gets a CAP's raw supported values.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapValues(CAP cap, out TW_CAPABILITY value)
{
value = new TW_CAPABILITY(cap);
return WrapInSTS(DGControl.Capability.Get(ref _appIdentity, ref _currentDS, ref value));
}
/// <summary>
/// Gets a CAP's supported values. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="values"></param>
/// <returns></returns>
public STS GetCapValues<TValue>(CAP cap, out IList<TValue> values) where TValue : struct
{
values = new List<TValue>();
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
{
case TWON.ONEVALUE:
values.Add(twcap.ReadOneValue<TValue>(this));
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.Items.Length > 0)
((List<TValue>)values).AddRange(twenum.Items);
break;
case TWON.RANGE:
// This can be slow
var twrange = twcap.ReadRange<TValue>(this);
((List<TValue>)values).AddRange(twrange);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0)
((List<TValue>)values).AddRange(twarr);
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <summary>
/// Gets a CAP's help text (description).
/// This may not work due to unclear spec.
/// </summary>
/// <param name="cap"></param>
/// <param name="help"></param>
/// <returns></returns>
public STS GetCapHelp(CAP cap, out string? help)
{
help = null;
var value = new TW_CAPABILITY(cap);
var rc = DGControl.Capability.GetHelp(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
help = value.ReadString(this, false);
}
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Gets a CAP's text name label.
/// This may not work due to unclear spec.
/// </summary>
/// <param name="cap"></param>
/// <param name="label"></param>
/// <returns></returns>
public STS GetCapLabel(CAP cap, out string? label)
{
label = null;
var value = new TW_CAPABILITY(cap) { ConType = TWON.ONEVALUE };
var rc = DGControl.Capability.GetLabel(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
label = value.ReadString(this, false);
}
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Gets a CAP's enum/array value label texts.
/// </summary>
/// <param name="cap"></param>
/// <param name="labels"></param>
/// <returns></returns>
public STS GetCapLabelEnum(CAP cap, out IList<string> labels)
{
labels = Array.Empty<string>();
var value = new TW_CAPABILITY(cap);
var rc = DGControl.Capability.GetLabelEnum(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
// spec says they're utf8
labels = value.ReadArray<TW_STR255>(this, false).Select(t => t.Get(Encoding.UTF8)).ToList();
}
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Sets a CAP's current value.
/// An easy way to create a value is to use the
/// <see cref="ValueWriter.CreateOneValueCap{TValue}(CAP, IMemoryManager, TValue)"/>
/// extension method (or the other container variants).
/// Memory of the value will be freed afterwards.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public STS SetCap(ref TW_CAPABILITY value)
{
var rc = DGControl.Capability.Set(ref _appIdentity, ref _currentDS, ref value);
value.Free(this);
if (value.Cap == CAP.CAP_LANGUAGE && rc == TWRC.SUCCESS)
{
RefreshCapLanguage();
}
return WrapInSTS(rc);
}
/// <summary>
/// A simpler cap value setter for common one-value scenarios
/// that's easier to use. Not for other container type sets.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS SetCap<TValue>(CAP cap, TValue value) where TValue : struct
{
var twcap = ValueWriter.CreateOneValueCap(cap, this, value);
return SetCap(ref twcap);
}
/// <summary>
/// Sets a CAP's constraint values.
/// An easy way to create a value is to use the
/// <see cref="ValueWriter.CreateOneValueCap{TValue}(CAP, IMemoryManager, TValue)"/>
/// extension method (or the other container variants).
/// Memory of the value will be freed afterwards.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public STS SetConstraint(ref TW_CAPABILITY value)
{
var rc = DGControl.Capability.SetConstraint(ref _appIdentity, ref _currentDS, ref value);
value.Free(this);
return WrapInSTS(rc);
}
/// <summary>
/// Resets a CAP's current value to power-on default.
/// Caller will need to manually read and free the memory.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS ResetCap(CAP cap, out TW_CAPABILITY value)
{
value = new TW_CAPABILITY(cap);
var rc = DGControl.Capability.Reset(ref _appIdentity, ref _currentDS, ref value);
if (value.Cap == CAP.CAP_LANGUAGE && rc == TWRC.SUCCESS)
{
RefreshCapLanguage();
}
return WrapInSTS(rc);
}
/// <summary>
/// Resets a CAP's current value to power-on default.
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS ResetCap<TValue>(CAP cap, out TValue value) where TValue : struct
{
value = default;
var sts = ResetCap(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
{
case TWON.ONEVALUE:
value = twcap.ReadOneValue<TValue>(this);
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumeration<TValue>(this);
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
{
value = twenum.Items[twenum.CurrentIndex];
}
break;
case TWON.RANGE:
value = twcap.ReadRange<TValue>(this).CurrentValue;
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0) value = twarr[0];
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <summary>
/// Resets all CAP values and constraint to power-on defaults.
/// </summary>
/// <returns></returns>
public STS ResetAllCaps()
{
// no memory is allocated for this
var value = new TW_CAPABILITY(CAP.CAP_SUPPORTEDCAPS);
var rc = DGControl.Capability.ResetAll(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
RefreshCapLanguage();
}
return WrapInSTS(rc);
}
private void RefreshCapLanguage()
{
var rc2 = GetCapCurrent(CAP.CAP_LANGUAGE, out List<TWLG> lang);
if (rc2.RC == TWRC.SUCCESS && lang.Count > 0)
{
Language.Set(lang.First());
}
break;
case TWON.RANGE:
value = twcap.ReadRange<TValue>(this).CurrentValue;
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0) value = twarr[0];
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <summary>
/// Resets all CAP values and constraint to power-on defaults.
/// </summary>
/// <returns></returns>
public STS ResetAllCaps()
{
// no memory is allocated for this
var value = new TW_CAPABILITY(CAP.CAP_SUPPORTEDCAPS);
var rc = DGControl.Capability.ResetAll(ref _appIdentity, ref _currentDS, ref value);
if (rc == TWRC.SUCCESS)
{
RefreshCapLanguage();
}
return WrapInSTS(rc);
}
private void RefreshCapLanguage()
{
var rc2 = GetCapCurrent(CAP.CAP_LANGUAGE, out List<TWLG> lang);
if (rc2.RC == TWRC.SUCCESS && lang.Count > 0)
{
Language.Set(lang.First());
}
}
}
}

View File

@@ -0,0 +1,37 @@
using NTwain.Data;
using NTwain.Triplets;
using System.Collections.Generic;
namespace NTwain;
// this file contains FileSystem mgmt methods
partial class TwainAppSession
{
/// <summary>
/// Enumerate file system items at current level.
/// </summary>
/// <returns></returns>
public IEnumerable<TW_FILESYSTEM> GetFileSystemItems()
{
TW_FILESYSTEM fs = default;
for (var rc = DGControl.FileSystem.GetFirstFile(ref _appIdentity, ref _currentDS, ref fs);
rc == TWRC.SUCCESS;
rc = DGControl.FileSystem.GetNextFile(ref _appIdentity, ref _currentDS, ref fs))
{
yield return fs;
}
}
/// <summary>
/// Try to change to a different directory.
/// </summary>
/// <param name="type"></param>
/// <param name="path"></param>
/// <returns></returns>
public STS ChangeFileSystemDirectory(TWFY type, string path)
{
TW_FILESYSTEM fs = new() { FileType = (int)type, InputName = path };
return WrapInSTS(DGControl.FileSystem.ChangeDirectory(ref _appIdentity, ref _currentDS, ref fs));
}
}