7 Commits

Author SHA1 Message Date
Eugene Wang
ce96d0c361 Attempt to make boxed version of cap value reads. 2025-11-20 22:56:23 -05:00
Eugene Wang
de788ce91d Test reading some values boxed. 2025-11-20 22:36:36 -05:00
Eugene Wang
2ae7293c44 Fix build errors and warnings. 2025-11-20 20:46:15 -05:00
Eugene Wang
1173c11961 Fix wrong cap call for Get. 2025-11-20 20:28:07 -05:00
Eugene Wang
8949b36833 Changed to return value container for available cap value to prevent long range enumerations. 2025-11-20 13:18:21 -05:00
Eugene Wang
36c7dd11ca Fix ICAP_SKEWANGLE value type to int. 2025-11-20 09:18:04 -05:00
Eugene Wang
2167d74fdc Added rest of kodak caps as properties. 2025-11-20 08:52:14 -05:00
16 changed files with 1547 additions and 618 deletions

View File

@@ -36,11 +36,11 @@ namespace ScannerTester
//_ = _twain.OpenDSMAsync();
}
protected override void OnClosed(EventArgs e)
protected override void OnFormClosed(FormClosedEventArgs e)
{
_twain.CloseDSM();
//_ = _twain.CloseDSMAsync();
base.OnClosed(e);
base.OnFormClosed(e);
}
private void _twain_Transferred(TwainAppSession sender, TransferredEventArgs e)
@@ -196,14 +196,14 @@ namespace ScannerTester
});
}
protected override void OnClosing(CancelEventArgs e)
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (_twain.State > STATE.S5)
{
e.Cancel = true;
}
_twain.TryStepdown(STATE.S2);
base.OnClosing(e);
base.OnFormClosing(e);
}
private void btnSelectScanner_Click(object sender, EventArgs e)
@@ -247,7 +247,7 @@ namespace ScannerTester
private void LoadSettings()
{
var mechs = _twain.Caps.ICAP_XFERMECH.Get();
var mechs = _twain.Caps.ICAP_XFERMECH.Get().GetValues();
if (!mechs.Contains(TWSX.FILE))
{
@@ -263,7 +263,7 @@ namespace ScannerTester
LogIt("Set unit to inches", sts);
}
var dpis = _twain.Caps.ICAP_XRESOLUTION.Get();
var dpis = _twain.Caps.ICAP_XRESOLUTION.Get().GetValues();
listDpi.Items.Clear();
if (dpis.Contains(200))
{
@@ -284,7 +284,7 @@ namespace ScannerTester
LogIt("300 DPI doesn't appear to be supported.");
}
var formats = _twain.Caps.ICAP_IMAGEFILEFORMAT.Get();
var formats = _twain.Caps.ICAP_IMAGEFILEFORMAT.Get().GetValues();
listFormat.Items.Clear();
foreach (var format in formats)
{

View File

@@ -1,17 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationManifest>app.manifest</ApplicationManifest>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<PlatformTarget>x86</PlatformTarget>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<ApplicationVisualStyles>true</ApplicationVisualStyles>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel element will disable file and registry virtualization.
Remove this element if your application requires this virtualization for backwards
compatibility.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config.
Makes the application long-path aware. See https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@@ -1,5 +1,6 @@
using Microsoft.Win32;
using NTwain;
using NTwain.Caps;
using NTwain.Data;
using System;
using System.Collections.Generic;
@@ -14,10 +15,10 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormSample
namespace WinFormSample;
public partial class Form1 : Form
{
public partial class Form1 : Form
{
bool useDiyPump = true;
TwainAppSession twain;
readonly string saveFolder;
@@ -31,275 +32,277 @@ namespace WinFormSample
public Form1()
{
InitializeComponent();
var libVer = FileVersionInfo.GetVersionInfo(typeof(TwainAppSession).Assembly.Location).ProductVersion;
Text += $"{(TWPlatform.Is32bit ? " 32bit" : " 64bit")} on NTwain {libVer}";
InitializeComponent();
var libVer = FileVersionInfo.GetVersionInfo(typeof(TwainAppSession).Assembly.Location).ProductVersion;
Text += $"{(TWPlatform.Is32bit ? " 32bit" : " 64bit")} on NTwain {libVer}";
TWPlatform.PreferLegacyDSM = false;
TWPlatform.PreferLegacyDSM = false;
twain = new TwainAppSession();
twain.StateChanged += Twain_StateChanged;
twain.DefaultSourceChanged += Twain_DefaultSourceChanged;
twain.CurrentSourceChanged += Twain_CurrentSourceChanged;
twain.SourceDisabled += Twain_SourceDisabled;
twain.TransferReady += Twain_TransferReady;
twain.Transferred += Twain_Transferred;
twain.TransferError += Twain_TransferError;
twain.DeviceEvent += Twain_DeviceEvent;
twain = new TwainAppSession();
twain.StateChanged += Twain_StateChanged;
twain.DefaultSourceChanged += Twain_DefaultSourceChanged;
twain.CurrentSourceChanged += Twain_CurrentSourceChanged;
twain.SourceDisabled += Twain_SourceDisabled;
twain.TransferReady += Twain_TransferReady;
twain.Transferred += Twain_Transferred;
twain.TransferError += Twain_TransferError;
twain.DeviceEvent += Twain_DeviceEvent;
capListView.SetDoubleBufferedAsNeeded();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
capListView.SetDoubleBufferedAsNeeded();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
saveFolder = Path.Combine(Path.GetTempPath(), "ntwain-sample" + Path.DirectorySeparatorChar);
Directory.CreateDirectory(saveFolder);
saveFolder = Path.Combine(Path.GetTempPath(), "ntwain-sample" + Path.DirectorySeparatorChar);
Directory.CreateDirectory(saveFolder);
this.Disposed += Form1_Disposed;
this.Disposed += Form1_Disposed;
_jpegParameters = new EncoderParameters(1);
_jpegParameters.Param[0] = new EncoderParameter(Encoder.Quality, (long)_jpegQuality);
_jpegEncoder = ImageCodecInfo.GetImageEncoders().First(enc => enc.FormatID == ImageFormat.Jpeg.Guid);
_jpegParameters = new EncoderParameters(1);
_jpegParameters.Param[0] = new EncoderParameter(Encoder.Quality, (long)_jpegQuality);
_jpegEncoder = ImageCodecInfo.GetImageEncoders().First(enc => enc.FormatID == ImageFormat.Jpeg.Guid);
}
private void Twain_SourceDisabled(TwainAppSession sender, TW_IDENTITY_LEGACY e)
{
BeginInvoke(() =>
{
if (watch.IsRunning)
BeginInvoke(() =>
{
watch.Stop();
MessageBox.Show($"Took {watch.Elapsed} to finish that transfer.");
}
});
if (watch.IsRunning)
{
watch.Stop();
MessageBox.Show($"Took {watch.Elapsed} to finish that transfer.");
}
});
}
private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
switch (e.Reason)
{
case SessionSwitchReason.RemoteConnect:
case SessionSwitchReason.SessionUnlock:
case SessionSwitchReason.SessionLogon:
capListView.SetDoubleBufferedAsNeeded();
break;
}
switch (e.Reason)
{
case SessionSwitchReason.RemoteConnect:
case SessionSwitchReason.SessionUnlock:
case SessionSwitchReason.SessionLogon:
capListView.SetDoubleBufferedAsNeeded();
break;
}
}
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
base.OnHandleCreated(e);
if (useDiyPump)
{
var sts = await twain.OpenDSMAsync();
Debug.WriteLine($"OpenDSMAsync={sts}");
}
else
{
var hwnd = this.Handle;
var sts = twain.OpenDSM(hwnd, SynchronizationContext.Current!);
twain.AddWinformFilter();
Debug.WriteLine($"OpenDSM={sts}");
}
if (useDiyPump)
{
var sts = await twain.OpenDSMAsync();
Debug.WriteLine($"OpenDSMAsync={sts}");
}
else
{
var hwnd = this.Handle;
var sts = twain.OpenDSM(hwnd, SynchronizationContext.Current!);
twain.AddWinformFilter();
Debug.WriteLine($"OpenDSM={sts}");
}
}
protected override void OnClosing(CancelEventArgs e)
protected override void OnFormClosing(FormClosingEventArgs e)
{
var finalState = twain.TryStepdown(STATE.S2);
Debug.WriteLine($"Stepdown result state={finalState}");
twain.RemoveWinformFilter();
base.OnClosing(e);
var finalState = twain.TryStepdown(STATE.S2);
Debug.WriteLine($"Stepdown result state={finalState}");
twain.RemoveWinformFilter();
base.OnFormClosing(e);
}
private void Form1_Disposed(object? sender, EventArgs e)
{
twain.Dispose();
twain.Dispose();
}
private void Twain_DeviceEvent(TwainAppSession sender, TW_DEVICEEVENT e)
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] device event {e}.");
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] device event {e}.");
}
private void Twain_TransferError(TwainAppSession sender, TransferErrorEventArgs e)
{
if (e.Exception != null)
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] transfer error {e.Exception}.");
}
else
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] transfer error {e.Code}.");
}
if (e.Exception != null)
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] transfer error {e.Exception}.");
}
else
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] transfer error {e.Code}.");
}
}
private void Twain_Transferred(TwainAppSession sender, TransferredEventArgs e)
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] data transferred with info {e.ImageInfo}");
// if using a high-speed scanner, imaging handling could be a bottleneck
// so it's possible to pass the data to another thread while the scanning
// loop happens. Just remember to dispose it after.
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] data transferred with info {e.ImageInfo}");
// if using a high-speed scanner, imaging handling could be a bottleneck
// so it's possible to pass the data to another thread while the scanning
// loop happens. Just remember to dispose it after.
if (_useThreadForImag)
{
// bad thread example but whatev. should use a dedicated thread of some sort for real
Task.Run(() =>
if (_useThreadForImag)
{
HandleTransferredData(e);
});
}
else
{
HandleTransferredData(e);
}
// bad thread example but whatev. should use a dedicated thread of some sort for real
Task.Run(() =>
{
HandleTransferredData(e);
});
}
else
{
HandleTransferredData(e);
}
}
private void HandleTransferredData(TransferredEventArgs e)
{
if (e.Data != null)
{
try
if (e.Data != null)
{
// example of using some lib to handle image data
var saveFile = Path.Combine(saveFolder, (DateTime.Now.Ticks / 1000).ToString());
try
{
// example of using some lib to handle image data
var saveFile = Path.Combine(saveFolder, (DateTime.Now.Ticks / 1000).ToString());
if (_useSystemDrawing)
{
using (var img = Image.FromStream(e.Data.AsStream()))
{
if (img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format1bppIndexed ||
img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
{
// bw or gray
saveFile += ".png";
if (_saveDisk) img.Save(saveFile, ImageFormat.Png);
else img.Save(new NoOpStream(), ImageFormat.Png);
}
else
{
// color
saveFile += ".jpg";
if (_saveDisk) img.Save(saveFile, _jpegEncoder, _jpegParameters);
else img.Save(new NoOpStream(), _jpegEncoder, _jpegParameters);
}
if (_useSystemDrawing)
{
using (var img = Image.FromStream(e.Data.AsStream()))
{
if (img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format1bppIndexed ||
img.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
{
// bw or gray
saveFile += ".png";
if (_saveDisk) img.Save(saveFile, ImageFormat.Png);
else img.Save(new NoOpStream(), ImageFormat.Png);
}
else
{
// color
saveFile += ".jpg";
if (_saveDisk) img.Save(saveFile, _jpegEncoder, _jpegParameters);
else img.Save(new NoOpStream(), _jpegEncoder, _jpegParameters);
}
}
}
else
{
using (var img = new ImageMagick.MagickImage(e.Data.AsSpan()))
{
var format = ImageMagick.MagickFormat.Png;
if (img.ColorType == ImageMagick.ColorType.Palette)
{
// bw or gray
saveFile += ".png";
}
else
{
// color
saveFile += ".jpg";
format = ImageMagick.MagickFormat.Jpeg;
img.Quality = (uint)_jpegQuality;
}
if (_saveDisk) img.Write(saveFile);
else img.Write(new NoOpStream(), format);
}
Debug.WriteLine($"Saved image to {saveFile}");
}
}
}
else
{
using (var img = new ImageMagick.MagickImage(e.Data.AsSpan()))
catch { }
finally
{
var format = ImageMagick.MagickFormat.Png;
if (img.ColorType == ImageMagick.ColorType.Palette)
{
// bw or gray
saveFile += ".png";
}
else
{
// color
saveFile += ".jpg";
format = ImageMagick.MagickFormat.Jpeg;
img.Quality = (uint)_jpegQuality;
}
if (_saveDisk) img.Write(saveFile);
else img.Write(new NoOpStream(), format);
e.Dispose();
}
Debug.WriteLine($"Saved image to {saveFile}");
}
}
catch { }
finally
{
e.Dispose();
}
}
}
private void Twain_TransferReady(TwainAppSession sender, TransferReadyEventArgs e)
{
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] transfer ready.");
Debug.WriteLine($"[thread {Environment.CurrentManagedThreadId}] transfer ready.");
}
private void Twain_DefaultSourceChanged(TwainAppSession sender, TW_IDENTITY_LEGACY ds)
{
BeginInvoke(() => lblDefault.Text = ds.ProductName);
BeginInvoke(() => lblDefault.Text = ds.ProductName);
}
private void Twain_StateChanged(TwainAppSession sender, STATE state)
{
BeginInvoke(() => lblState.Text = state.ToString());
BeginInvoke(() => lblState.Text = state.ToString());
}
private void Twain_CurrentSourceChanged(TwainAppSession sender, TW_IDENTITY_LEGACY ds)
{
BeginInvoke(() =>
{
lblCurrent.Text = ds.ToString();
if (twain.State == STATE.S4)
BeginInvoke(() =>
{
LoadCapInfoList();
lblCurrent.Text = ds.ToString();
if (twain.State == STATE.S4)
{
LoadCapInfoList();
// never seen a driver support these but here it is to test it
if (twain.GetCapLabel(CAP.ICAP_SUPPORTEDSIZES, out string? test).RC == TWRC.SUCCESS)
{
Debug.WriteLine($"Supported sizes label from ds = {test}");
}
if (twain.GetCapHelp(CAP.ICAP_SUPPORTEDSIZES, out string? test2).RC == TWRC.SUCCESS)
{
Debug.WriteLine($"Supported sizes help from ds = {test2}");
}
if (twain.GetCapLabelEnum(CAP.ICAP_SUPPORTEDSIZES, out IList<string>? test3).RC == TWRC.SUCCESS && test3 != null)
{
Debug.WriteLine($"Supported sizes label enum from ds = {string.Join(Environment.NewLine, test3)}");
}
}
else
{
capListView.Items.Clear();
}
});
// never seen a driver support these but here it is to test it
if (twain.GetCapLabel(CAP.ICAP_SUPPORTEDSIZES, out string? test).RC == TWRC.SUCCESS)
{
Debug.WriteLine($"Supported sizes label from ds = {test}");
}
if (twain.GetCapHelp(CAP.ICAP_SUPPORTEDSIZES, out string? test2).RC == TWRC.SUCCESS)
{
Debug.WriteLine($"Supported sizes help from ds = {test2}");
}
if (twain.GetCapLabelEnum(CAP.ICAP_SUPPORTEDSIZES, out IList<string>? test3).RC == TWRC.SUCCESS && test3 != null)
{
Debug.WriteLine($"Supported sizes label enum from ds = {string.Join(Environment.NewLine, test3)}");
}
}
else
{
capListView.Items.Clear();
}
});
}
private void LoadCapInfoList()
{
twain.GetCapValues(CAP.CAP_SUPPORTEDCAPS, out IList<CAP> caps);
twain.GetCapValues(CAP.CAP_EXTENDEDCAPS, out IList<CAP> extended);
foreach (var c in caps)
{
ListViewItem it = new(GetFriendlyName(c));
twain.GetCapValues(CAP.CAP_SUPPORTEDCAPS, out ValueContainer<CAP> capsContainer);
twain.GetCapValues(CAP.CAP_EXTENDEDCAPS, out ValueContainer<CAP> extendedContainer);
var caps = capsContainer.GetValues().ToList();
var extended = extendedContainer.GetValues().ToList();
foreach (var c in caps)
{
ListViewItem it = new(GetFriendlyName(c));
if (twain.GetCapCurrent(c, out TW_CAPABILITY twcap).RC == TWRC.SUCCESS)
{
var enumType = SizeAndConversionUtils.GetEnumType(c);
var realType = twcap.DetermineValueType(twain);
it.SubItems.Add(enumType?.Name.ToString() ?? realType.ToString());
it.SubItems.Add(ReadTypedValue(c, enumType, realType, forCurrent: true));
it.SubItems.Add(ReadTypedValue(c, enumType, realType, forCurrent: false));
if (twain.GetCapCurrent(c, out TW_CAPABILITY twcap).RC == TWRC.SUCCESS)
{
var enumType = SizeAndConversionUtils.GetEnumType(c);
var realType = twcap.DetermineValueType(twain);
it.SubItems.Add(enumType?.Name.ToString() ?? realType.ToString());
it.SubItems.Add(ReadTypedValue(c, enumType, realType, forCurrent: true));
it.SubItems.Add(ReadTypedValue(c, enumType, realType, forCurrent: false));
}
else
{
it.SubItems.Add("");
it.SubItems.Add("");
it.SubItems.Add("");
}
it.SubItems.Add(extended.Contains(c).ToString());
var supports = twain.QueryCapSupport(c);
it.SubItems.Add(supports.ToString());
if (!supports.HasFlag(TWQC.SET)) it.ForeColor = Color.Gray;
capListView.Items.Add(it);
}
else
{
it.SubItems.Add("");
it.SubItems.Add("");
it.SubItems.Add("");
}
it.SubItems.Add(extended.Contains(c).ToString());
var supports = twain.QueryCapSupport(c);
it.SubItems.Add(supports.ToString());
if (!supports.HasFlag(TWQC.SET)) it.ForeColor = Color.Gray;
capListView.Items.Add(it);
}
}
private string GetFriendlyName(CAP c)
{
if (c > CAP.CAP_CUSTOMBASE)
{
return $"{CAP.CAP_CUSTOMBASE} + {c - CAP.CAP_CUSTOMBASE}";
}
return c.ToString();
if (c > CAP.CAP_CUSTOMBASE)
{
return $"{CAP.CAP_CUSTOMBASE} + {c - CAP.CAP_CUSTOMBASE}";
}
return c.ToString();
}
// there may be a better way...
@@ -307,189 +310,188 @@ namespace WinFormSample
private string ReadTypedValue(CAP cap, Type? enumType, TWTY type, bool forCurrent)
{
if (enumType != null)
{
if (forCurrent)
if (enumType != null)
{
var currentMethod = twainMethods
.FirstOrDefault(m => m.Name == nameof(TwainAppSession.GetCapCurrent) && m.IsGenericMethod)!
.MakeGenericMethod(enumType);
var args = new object?[] { cap, null };
currentMethod.Invoke(twain, args);
var values = (System.Collections.IList)args[1]!;
if (values.Count == 1)
{
return values[0]!.ToString()!;
}
else if (values.Count > 1)
{
return string.Join(", ", values);
}
return "";
if (forCurrent)
{
var currentMethod = twainMethods
.FirstOrDefault(m => m.Name == nameof(TwainAppSession.GetCapCurrent) && m.IsGenericMethod)!
.MakeGenericMethod(enumType);
var args = new object?[] { cap, null };
currentMethod.Invoke(twain, args);
var values = (System.Collections.IList)args[1]!;
if (values.Count == 1)
{
return values[0]!.ToString()!;
}
else if (values.Count > 1)
{
return string.Join(", ", values);
}
return "";
}
else
{
var defaultMethod = twainMethods
.FirstOrDefault(m => m.Name == nameof(TwainAppSession.GetCapDefault) && m.IsGenericMethod)!
.MakeGenericMethod(enumType);
var args = new object?[] { cap, null };
defaultMethod.Invoke(twain, args);
var values = (System.Collections.IList)args[1]!;
if (values.Count == 1)
{
return values[0]!.ToString()!;
}
else if (values.Count > 1)
{
return string.Join(", ", values);
}
return "";
}
}
else
{
var defaultMethod = twainMethods
.FirstOrDefault(m => m.Name == nameof(TwainAppSession.GetCapDefault) && m.IsGenericMethod)!
.MakeGenericMethod(enumType);
var args = new object?[] { cap, null };
defaultMethod.Invoke(twain, args);
var values = (System.Collections.IList)args[1]!;
if (values.Count == 1)
{
return values[0]!.ToString()!;
}
else if (values.Count > 1)
{
return string.Join(", ", values);
}
return "";
}
}
STS sts = default;
switch (type)
{
case TWTY.UINT8:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<byte> ubval) :
twain.GetCapDefault(cap, out ubval);
return ubval.FirstOrDefault().ToString();
case TWTY.INT8:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<sbyte> sbval) :
twain.GetCapDefault(cap, out sbval);
return sbval.FirstOrDefault().ToString();
case TWTY.UINT16:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<ushort> usval) :
twain.GetCapDefault(cap, out usval);
return usval.FirstOrDefault().ToString();
case TWTY.INT16:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<short> ssval) :
twain.GetCapDefault(cap, out ssval);
return ssval.FirstOrDefault().ToString();
case TWTY.UINT32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<uint> uival) :
twain.GetCapDefault(cap, out uival);
return uival.FirstOrDefault().ToString();
case TWTY.INT32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<int> sival) :
twain.GetCapDefault(cap, out sival);
return sival.FirstOrDefault().ToString();
case TWTY.BOOL:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_BOOL> tbval) :
twain.GetCapDefault(cap, out tbval);
return tbval.FirstOrDefault().ToString();
case TWTY.FIX32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_FIX32> fxval) :
twain.GetCapDefault(cap, out fxval);
return fxval.FirstOrDefault().ToString();
case TWTY.FRAME:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_FRAME> frval) :
twain.GetCapDefault(cap, out frval);
return frval.FirstOrDefault().ToString();
case TWTY.STR32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR32> s32val) :
twain.GetCapDefault(cap, out s32val);
return s32val.FirstOrDefault().ToString();
case TWTY.STR64:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR64> s64val) :
twain.GetCapDefault(cap, out s64val);
return s64val.FirstOrDefault().ToString();
case TWTY.STR128:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR128> s128val) :
twain.GetCapDefault(cap, out s128val);
return s128val.FirstOrDefault().ToString();
case TWTY.STR255:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR255> s255val) :
twain.GetCapDefault(cap, out s255val);
return s255val.FirstOrDefault().ToString();
case TWTY.HANDLE:
break;
}
Debug.WriteLine($"{nameof(ReadTypedValue)}({cap}, {type}, {forCurrent}) => {sts}");
return "";
STS sts = default;
switch (type)
{
case TWTY.UINT8:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<byte> ubval) :
twain.GetCapDefault(cap, out ubval);
return ubval.FirstOrDefault().ToString();
case TWTY.INT8:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<sbyte> sbval) :
twain.GetCapDefault(cap, out sbval);
return sbval.FirstOrDefault().ToString();
case TWTY.UINT16:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<ushort> usval) :
twain.GetCapDefault(cap, out usval);
return usval.FirstOrDefault().ToString();
case TWTY.INT16:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<short> ssval) :
twain.GetCapDefault(cap, out ssval);
return ssval.FirstOrDefault().ToString();
case TWTY.UINT32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<uint> uival) :
twain.GetCapDefault(cap, out uival);
return uival.FirstOrDefault().ToString();
case TWTY.INT32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<int> sival) :
twain.GetCapDefault(cap, out sival);
return sival.FirstOrDefault().ToString();
case TWTY.BOOL:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_BOOL> tbval) :
twain.GetCapDefault(cap, out tbval);
return tbval.FirstOrDefault().ToString();
case TWTY.FIX32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_FIX32> fxval) :
twain.GetCapDefault(cap, out fxval);
return fxval.FirstOrDefault().ToString();
case TWTY.FRAME:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_FRAME> frval) :
twain.GetCapDefault(cap, out frval);
return frval.FirstOrDefault().ToString();
case TWTY.STR32:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR32> s32val) :
twain.GetCapDefault(cap, out s32val);
return s32val.FirstOrDefault().ToString();
case TWTY.STR64:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR64> s64val) :
twain.GetCapDefault(cap, out s64val);
return s64val.FirstOrDefault().ToString();
case TWTY.STR128:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR128> s128val) :
twain.GetCapDefault(cap, out s128val);
return s128val.FirstOrDefault().ToString();
case TWTY.STR255:
sts = forCurrent ?
twain.GetCapCurrent(cap, out List<TW_STR255> s255val) :
twain.GetCapDefault(cap, out s255val);
return s255val.FirstOrDefault().ToString();
case TWTY.HANDLE:
break;
}
Debug.WriteLine($"{nameof(ReadTypedValue)}({cap}, {type}, {forCurrent}) => {sts}");
return "";
}
private void btnSelect_Click(object sender, EventArgs e)
{
twain.ShowUserSelect();
twain.ShowUserSelect();
}
private void btnEnumSources_Click(object sender, EventArgs e)
{
listSources.Items.Clear();
foreach (var ds in twain.GetSources())
{
listSources.Items.Add(ds);
}
listSources.Items.Clear();
foreach (var ds in twain.GetSources())
{
listSources.Items.Add(ds);
}
}
private void btnSetDef_Click(object sender, EventArgs e)
{
if (listSources.SelectedItem is TW_IDENTITY_LEGACY ds)
{
twain.SetDefaultSource(ds);
}
if (listSources.SelectedItem is TW_IDENTITY_LEGACY ds)
{
twain.SetDefaultSource(ds);
}
}
private void btnOpen_Click(object sender, EventArgs e)
{
if (listSources.SelectedItem is TW_IDENTITY_LEGACY ds)
{
twain.TryStepdown(STATE.S3);
if (listSources.SelectedItem is TW_IDENTITY_LEGACY ds)
{
twain.TryStepdown(STATE.S3);
twain.OpenSource(ds);
}
twain.OpenSource(ds);
}
}
private void btnClose_Click(object sender, EventArgs e)
{
twain.CloseSource();
twain.CloseSource();
}
private void btnOpenDef_Click(object sender, EventArgs e)
{
twain.TryStepdown(STATE.S3);
twain.TryStepdown(STATE.S3);
twain.OpenSource(twain.DefaultSource);
twain.OpenSource(twain.DefaultSource);
}
private void btnShowSettings_Click(object sender, EventArgs e)
{
twain.EnableSource(true, true);
twain.EnableSource(true, true);
}
private void btnStart_Click(object sender, EventArgs e)
{
if (twain.EnableSource(ckShowUI.Checked, false).IsSuccess)
{
_useThreadForImag = ckBgImageHandling.Checked;
_useSystemDrawing = ckSystemDrawing.Checked;
_saveDisk = ckSaveDisk.Checked;
watch.Restart();
}
if (twain.EnableSource(ckShowUI.Checked, false).IsSuccess)
{
_useThreadForImag = ckBgImageHandling.Checked;
_useSystemDrawing = ckSystemDrawing.Checked;
_saveDisk = ckSaveDisk.Checked;
watch.Restart();
}
}
private void btnOpenFolder_Click(object sender, EventArgs e)
{
try
{
if (!Directory.Exists(saveFolder)) Directory.CreateDirectory(saveFolder);
using (Process.Start(new ProcessStartInfo { FileName = saveFolder, UseShellExecute = true })) { }
}
catch { }
try
{
if (!Directory.Exists(saveFolder)) Directory.CreateDirectory(saveFolder);
using (Process.Start(new ProcessStartInfo { FileName = saveFolder, UseShellExecute = true })) { }
}
catch { }
}
}
}

View File

@@ -6,24 +6,26 @@
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<PlatformTarget>x86</PlatformTarget>
<RootNamespace>WinFormSample</RootNamespace>
<RootNamespace>WinFormSample</RootNamespace>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<ApplicationVisualStyles>true</ApplicationVisualStyles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Magick.NET-Q8-x86" Version="14.9.1" />
<PackageReference Include="Magick.NET-Q8-x86" Version="14.9.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="platforms\qwindows.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="runtimes\win-x86\native\TWAINDSM.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="platforms\qwindows.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="runtimes\win-x86\native\TWAINDSM.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -1,37 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<PlatformTarget>x64</PlatformTarget>
<RootNamespace>WinFormSample</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<PlatformTarget>x64</PlatformTarget>
<RootNamespace>WinFormSample</RootNamespace>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
<ApplicationVisualStyles>true</ApplicationVisualStyles>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Magick.NET-Q8-x64" Version="14.9.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Magick.NET-Q8-x64" Version="14.9.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WinForm32\**\*.cs" Exclude="..\WinForm32\**\obj\**;..\WinForm32\**\bin\**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<EmbeddedResource Include="..\WinForm32\**\*.resx" Exclude="..\WinForm32\**\obj\**;..\WinForm32\**\bin\**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Include="..\WinForm32\**\*.cs" Exclude="..\WinForm32\**\obj\**;..\WinForm32\**\bin\**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<EmbeddedResource Include="..\WinForm32\**\*.resx" Exclude="..\WinForm32\**\obj\**;..\WinForm32\**\bin\**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Update="platforms\qwindows.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="runtimes\win-x64\native\TWAINDSM.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="platforms\qwindows.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="runtimes\win-x64\native\TWAINDSM.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

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

View File

@@ -4,101 +4,97 @@ using System.Collections.Generic;
namespace NTwain.Caps
{
/// <summary>
///
/// </summary>
/// <typeparam name="TValue"></typeparam>
public class CapReader<TValue> where TValue : struct
{
protected readonly TwainAppSession _twain;
public CapReader(TwainAppSession twain, CAP cap, float introducedVersion = 1)
{
_twain = twain;
Cap = cap;
Introduced = introducedVersion;
}
public CAP Cap { get; }
/// <summary>
/// When this was introduced in TWAIN.
///
/// </summary>
public float Introduced { get; }
/// <summary>
/// The STS result from the most recent call with this cap wrapper.
/// </summary>
public STS LastSTS { get; protected set; }
TWQC? _qc;
public TWQC Supports
/// <typeparam name="TValue"></typeparam>
public class CapReader<TValue> where TValue : struct
{
get
{
if (!_qc.HasValue) _qc = _twain.QueryCapSupport(Cap);
return _qc.Value;
}
}
protected readonly TwainAppSession _twain;
public IList<TValue> Get()
{
LastSTS = _twain.GetCapValues(Cap, out IList<TValue> values);
if (LastSTS.IsSuccess)
{
return values;
};
return Array.Empty<TValue>();
}
public CapReader(TwainAppSession twain, CAP cap, float introducedVersion = 1)
{
_twain = twain;
Cap = cap;
Introduced = introducedVersion;
}
public IList<TValue> GetCurrent()
{
LastSTS = _twain.GetCapCurrent(Cap, out List<TValue> value);
if (LastSTS.IsSuccess)
{
return value;
};
return Array.Empty<TValue>();
}
public CAP Cap { get; }
public IList<TValue> GetDefault()
{
LastSTS = _twain.GetCapDefault(Cap, out List<TValue> value);
if (LastSTS.IsSuccess)
{
return value;
};
return Array.Empty<TValue>();
}
/// <summary>
/// When this was introduced in TWAIN.
/// </summary>
public float Introduced { get; }
public string? GetLabel()
{
LastSTS = _twain.GetCapLabel(Cap, out string? value);
if (LastSTS.IsSuccess)
{
return value;
};
return default;
}
/// <summary>
/// The STS result from the most recent call with this cap wrapper.
/// </summary>
public STS LastSTS { get; protected set; }
public string? GetHelp()
{
LastSTS = _twain.GetCapHelp(Cap, out string? value);
if (LastSTS.IsSuccess)
{
return value;
};
return default;
}
TWQC? _qc;
public TWQC Supports
{
get
{
if (!_qc.HasValue) _qc = _twain.QueryCapSupport(Cap);
return _qc.Value;
}
}
public IList<string> GetLabelEnum()
{
LastSTS = _twain.GetCapLabelEnum(Cap, out IList<string> value);
if (LastSTS.IsSuccess)
{
return value;
};
return Array.Empty<string>();
public ValueContainer<TValue> Get()
{
LastSTS = _twain.GetCapValues(Cap, out ValueContainer<TValue> value);
return value;
}
public IList<TValue> GetCurrent()
{
LastSTS = _twain.GetCapCurrent(Cap, out List<TValue> value);
if (LastSTS.IsSuccess)
{
return value;
}
return Array.Empty<TValue>();
}
public IList<TValue> GetDefault()
{
LastSTS = _twain.GetCapDefault(Cap, out List<TValue> value);
if (LastSTS.IsSuccess)
{
return value;
}
return Array.Empty<TValue>();
}
public string? GetLabel()
{
LastSTS = _twain.GetCapLabel(Cap, out string? value);
if (LastSTS.IsSuccess)
{
return value;
}
return default;
}
public string? GetHelp()
{
LastSTS = _twain.GetCapHelp(Cap, out string? value);
if (LastSTS.IsSuccess)
{
return value;
}
return default;
}
public IList<string> GetLabelEnum()
{
LastSTS = _twain.GetCapLabelEnum(Cap, out IList<string> value);
if (LastSTS.IsSuccess)
{
return value;
}
return Array.Empty<string>();
}
}
}
}

View File

@@ -117,4 +117,190 @@ partial class KdsCaps
public CapWriter<TWCBR> ICAP_COLORBRIGHTNESSMODE =>
_ICAP_COLORBRIGHTNESSMODE ??= new(_twain, (CAP)KDS_CAP.ICAP_COLORBRIGHTNESSMODE, 2);
// TODO: verify data types below
CapWriter<TW_BOOL>? _ICAP_LAMPSAVER;
public CapWriter<TW_BOOL> ICAP_LAMPSAVER =>
_ICAP_LAMPSAVER ??= new(_twain, (CAP)KDS_CAP.ICAP_LAMPSAVER, 2);
CapWriter<TW_FIX32>? _ICAP_OVERSCANX;
public CapWriter<TW_FIX32> ICAP_OVERSCANX =>
_ICAP_OVERSCANX ??= new(_twain, (CAP)KDS_CAP.ICAP_OVERSCANX, 2);
CapWriter<TW_FIX32>? _ICAP_OVERSCANY;
public CapWriter<TW_FIX32> ICAP_OVERSCANY =>
_ICAP_OVERSCANY ??= new(_twain, (CAP)KDS_CAP.ICAP_OVERSCANY, 2);
CapWriter<ushort>? _ICAP_FORCECOMPRESSION;
public CapWriter<ushort> ICAP_FORCECOMPRESSION =>
_ICAP_FORCECOMPRESSION ??= new(_twain, (CAP)KDS_CAP.ICAP_FORCECOMPRESSION, 2);
CapWriter<ushort>? _ICAP_HALFTONESQUALITY;
public CapWriter<ushort> ICAP_HALFTONESQUALITY =>
_ICAP_HALFTONESQUALITY ??= new(_twain, (CAP)KDS_CAP.ICAP_HALFTONESQUALITY, 2);
CapWriter<ushort>? _ICAP_COLORTABLE;
public CapWriter<ushort> ICAP_COLORTABLE =>
_ICAP_COLORTABLE ??= new(_twain, (CAP)KDS_CAP.ICAP_COLORTABLE, 2);
CapWriter<TW_BOOL>? _ICAP_VERTICALBLACKLINEREMOVAL;
public CapWriter<TW_BOOL> ICAP_VERTICALBLACKLINEREMOVAL =>
_ICAP_VERTICALBLACKLINEREMOVAL ??= new(_twain, (CAP)KDS_CAP.ICAP_VERTICALBLACKLINEREMOVAL, 2);
CapWriter<TW_BOOL>? _ICAP_ADDBORDER;
public CapWriter<TW_BOOL> ICAP_ADDBORDER =>
_ICAP_ADDBORDER ??= new(_twain, (CAP)KDS_CAP.ICAP_ADDBORDER, 2);
CapWriter<ushort>? _ICAP_FILTERENUM;
public CapWriter<ushort> ICAP_FILTERENUM =>
_ICAP_FILTERENUM ??= new(_twain, (CAP)KDS_CAP.ICAP_FILTERENUM, 2);
CapWriter<ushort>? _ICAP_FILTERTHRESHOLD;
public CapWriter<ushort> ICAP_FILTERTHRESHOLD =>
_ICAP_FILTERTHRESHOLD ??= new(_twain, (CAP)KDS_CAP.ICAP_FILTERTHRESHOLD, 2);
CapWriter<ushort>? _ICAP_FILTERBACKGROUND;
public CapWriter<ushort> ICAP_FILTERBACKGROUND =>
_ICAP_FILTERBACKGROUND ??= new(_twain, (CAP)KDS_CAP.ICAP_FILTERBACKGROUND, 2);
CapWriter<ushort>? _ICAP_LAMPTIMEOUT;
public CapWriter<ushort> ICAP_LAMPTIMEOUT =>
_ICAP_LAMPTIMEOUT ??= new(_twain, (CAP)KDS_CAP.ICAP_LAMPTIMEOUT, 2);
CapWriter<TW_BOOL>? _ICAP_GRAYSCALE;
public CapWriter<TW_BOOL> ICAP_GRAYSCALE =>
_ICAP_GRAYSCALE ??= new(_twain, (CAP)KDS_CAP.ICAP_GRAYSCALE, 2);
CapWriter<int>? _ICAP_COLORSHARPENING;
public CapWriter<int> ICAP_COLORSHARPENING =>
_ICAP_COLORSHARPENING ??= new(_twain, (CAP)KDS_CAP.ICAP_COLORSHARPENING, 2);
CapWriter<TW_BOOL>? _ICAP_FRAMELENGTHCONTROL;
public CapWriter<TW_BOOL> ICAP_FRAMELENGTHCONTROL =>
_ICAP_FRAMELENGTHCONTROL ??= new(_twain, (CAP)KDS_CAP.ICAP_FRAMELENGTHCONTROL, 2);
CapWriter<TW_BOOL>? _ICAP_FLIPBACKGROUNDCOLOR;
public CapWriter<TW_BOOL> ICAP_FLIPBACKGROUNDCOLOR =>
_ICAP_FLIPBACKGROUNDCOLOR ??= new(_twain, (CAP)KDS_CAP.ICAP_FLIPBACKGROUNDCOLOR, 2);
CapWriter<TW_BOOL>? _ICAP_GAMMAENABLED;
public CapWriter<TW_BOOL> ICAP_GAMMAENABLED =>
_ICAP_GAMMAENABLED ??= new(_twain, (CAP)KDS_CAP.ICAP_GAMMAENABLED, 2);
CapWriter<ushort>? _ICAP_FILTERPROCESSING;
public CapWriter<ushort> ICAP_FILTERPROCESSING =>
_ICAP_FILTERPROCESSING ??= new(_twain, (CAP)KDS_CAP.ICAP_FILTERPROCESSING, 2);
CapWriter<int>? _ICAP_AUTOCOLORAMOUNT;
public CapWriter<int> ICAP_AUTOCOLORAMOUNT =>
_ICAP_AUTOCOLORAMOUNT ??= new(_twain, (CAP)KDS_CAP.ICAP_AUTOCOLORAMOUNT, 2);
CapWriter<ushort>? _ICAP_AUTOCOLORCONTENT;
public CapWriter<ushort> ICAP_AUTOCOLORCONTENT =>
_ICAP_AUTOCOLORCONTENT ??= new(_twain, (CAP)KDS_CAP.ICAP_AUTOCOLORCONTENT, 2);
CapWriter<int>? _ICAP_AUTOCOLORTHRESHOLD;
public CapWriter<int> ICAP_AUTOCOLORTHRESHOLD =>
_ICAP_AUTOCOLORTHRESHOLD ??= new(_twain, (CAP)KDS_CAP.ICAP_AUTOCOLORTHRESHOLD, 2);
CapWriter<ushort>? _ICAP_PADDING;
public CapWriter<ushort> ICAP_PADDING =>
_ICAP_PADDING ??= new(_twain, (CAP)KDS_CAP.ICAP_PADDING, 2);
CapWriter<ushort>? _ICAP_NEWWINDOWSIZE;
public CapWriter<ushort> ICAP_NEWWINDOWSIZE =>
_ICAP_NEWWINDOWSIZE ??= new(_twain, (CAP)KDS_CAP.ICAP_NEWWINDOWSIZE, 2);
CapWriter<ushort>? _ICAP_DOCUMENTTYPE;
public CapWriter<ushort> ICAP_DOCUMENTTYPE =>
_ICAP_DOCUMENTTYPE ??= new(_twain, (CAP)KDS_CAP.ICAP_DOCUMENTTYPE, 2);
CapWriter<int>? _ICAP_SKEWANGLE;
public CapWriter<int> ICAP_SKEWANGLE =>
_ICAP_SKEWANGLE ??= new(_twain, (CAP)KDS_CAP.ICAP_SKEWANGLE, 2);
CapWriter<ushort>? _ICAP_MEDIATYPE;
public CapWriter<ushort> ICAP_MEDIATYPE =>
_ICAP_MEDIATYPE ??= new(_twain, (CAP)KDS_CAP.ICAP_MEDIATYPE, 2);
CapWriter<ushort>? _ICAP_ECDO;
public CapWriter<ushort> ICAP_ECDO =>
_ICAP_ECDO ??= new(_twain, (CAP)KDS_CAP.ICAP_ECDO, 2);
CapWriter<TW_BOOL>? _ICAP_ECDOTREATASCOLOR;
public CapWriter<TW_BOOL> ICAP_ECDOTREATASCOLOR =>
_ICAP_ECDOTREATASCOLOR ??= new(_twain, (CAP)KDS_CAP.ICAP_ECDOTREATASCOLOR, 2);
CapWriter<TW_FIX32>? _ICAP_PHYSICALHEIGHTADJUST;
public CapWriter<TW_FIX32> ICAP_PHYSICALHEIGHTADJUST =>
_ICAP_PHYSICALHEIGHTADJUST ??= new(_twain, (CAP)KDS_CAP.ICAP_PHYSICALHEIGHTADJUST, 2);
CapWriter<uint>? _ICAP_COLORSHARPEN;
public CapWriter<uint> ICAP_COLORSHARPEN =>
_ICAP_COLORSHARPEN ??= new(_twain, (CAP)KDS_CAP.ICAP_COLORSHARPEN, 2);
CapWriter<int>? _ICAP_ECDOAGGRESSIVENESS;
public CapWriter<int> ICAP_ECDOAGGRESSIVENESS =>
_ICAP_ECDOAGGRESSIVENESS ??= new(_twain, (CAP)KDS_CAP.ICAP_ECDOAGGRESSIVENESS, 2);
CapWriter<int>? _ICAP_FOREGROUNDBOLDNESSAGGRESSIVENESS;
public CapWriter<int> ICAP_FOREGROUNDBOLDNESSAGGRESSIVENESS =>
_ICAP_FOREGROUNDBOLDNESSAGGRESSIVENESS ??= new(_twain, (CAP)KDS_CAP.ICAP_FOREGROUNDBOLDNESSAGGRESSIVENESS, 2);
CapWriter<ushort>? _ICAP_FOREGROUNDBOLDNESSMODE;
public CapWriter<ushort> ICAP_FOREGROUNDBOLDNESSMODE =>
_ICAP_FOREGROUNDBOLDNESSMODE ??= new(_twain, (CAP)KDS_CAP.ICAP_FOREGROUNDBOLDNESSMODE, 2);
CapWriter<TW_BOOL>? _ICAP_TEXTENHANCEMENT;
public CapWriter<TW_BOOL> ICAP_TEXTENHANCEMENT =>
_ICAP_TEXTENHANCEMENT ??= new(_twain, (CAP)KDS_CAP.ICAP_TEXTENHANCEMENT, 2);
CapWriter<int>? _ICAP_THINTHICKENAMOUNT;
public CapWriter<int> ICAP_THINTHICKENAMOUNT =>
_ICAP_THINTHICKENAMOUNT ??= new(_twain, (CAP)KDS_CAP.ICAP_THINTHICKENAMOUNT, 2);
CapWriter<TW_BOOL>? _ICAP_ECDOINCLUDENONDROPPED;
public CapWriter<TW_BOOL> ICAP_ECDOINCLUDENONDROPPED =>
_ICAP_ECDOINCLUDENONDROPPED ??= new(_twain, (CAP)KDS_CAP.ICAP_ECDOINCLUDENONDROPPED, 2);
CapWriter<TW_BOOL>? _ICAP_AUTOCOLORIGNOREBACKGROUND;
public CapWriter<TW_BOOL> ICAP_AUTOCOLORIGNOREBACKGROUND =>
_ICAP_AUTOCOLORIGNOREBACKGROUND ??= new(_twain, (CAP)KDS_CAP.ICAP_AUTOCOLORIGNOREBACKGROUND, 2);
}

View File

@@ -50,4 +50,316 @@ public partial class KdsCaps
CapWriter<TWBK>? _CAP_BACKGROUND;
public CapWriter<TWBK> CAP_BACKGROUND =>
_CAP_BACKGROUND ??= new(_twain, (CAP)KDS_CAP.CAP_BACKGROUND, 2);
CapWriter<TWBK>? _CAP_BACKGROUNDFRONT;
public CapWriter<TWBK> CAP_BACKGROUNDFRONT =>
_CAP_BACKGROUNDFRONT ??= new(_twain, (CAP)KDS_CAP.CAP_BACKGROUNDFRONT, 2);
CapWriter<TWBK>? _CAP_BACKGROUNDREAR;
public CapWriter<TWBK> CAP_BACKGROUNDREAR =>
_CAP_BACKGROUNDREAR ??= new(_twain, (CAP)KDS_CAP.CAP_BACKGROUNDREAR, 2);
CapWriter<TWBK>? _CAP_BACKGROUNDPLATEN;
public CapWriter<TWBK> CAP_BACKGROUNDPLATEN =>
_CAP_BACKGROUNDPLATEN ??= new(_twain, (CAP)KDS_CAP.CAP_BACKGROUNDPLATEN, 2);
CapWriter<TW_FIX32>? _CAP_BATCHCOUNT;
public CapWriter<TW_FIX32> CAP_BATCHCOUNT =>
_CAP_BATCHCOUNT ??= new(_twain, (CAP)KDS_CAP.CAP_BATCHCOUNT, 2);
// TODO: verify data types below
CapWriter<TW_BOOL>? _CAP_BINARIZATION;
public CapWriter<TW_BOOL> CAP_BINARIZATION =>
_CAP_BINARIZATION ??= new(_twain, (CAP)KDS_CAP.CAP_BINARIZATION, 2);
CapWriter<TW_BOOL>? _CAP_CHECKDIGIT;
public CapWriter<TW_BOOL> CAP_CHECKDIGIT =>
_CAP_CHECKDIGIT ??= new(_twain, (CAP)KDS_CAP.CAP_CHECKDIGIT, 2);
CapWriter<TW_BOOL>? _CAP_DOUBLEFEEDENDJOB;
public CapWriter<TW_BOOL> CAP_DOUBLEFEEDENDJOB =>
_CAP_DOUBLEFEEDENDJOB ??= new(_twain, (CAP)KDS_CAP.CAP_DOUBLEFEEDENDJOB, 2);
CapWriter<TW_BOOL>? _CAP_DOUBLEFEEDSTOP;
public CapWriter<TW_BOOL> CAP_DOUBLEFEEDSTOP =>
_CAP_DOUBLEFEEDSTOP ??= new(_twain, (CAP)KDS_CAP.CAP_DOUBLEFEEDSTOP, 2);
CapWriter<TW_BOOL>? _CAP_EASYSTACKING;
public CapWriter<TW_BOOL> CAP_EASYSTACKING =>
_CAP_EASYSTACKING ??= new(_twain, (CAP)KDS_CAP.CAP_EASYSTACKING, 2);
CapWriter<TW_BOOL>? _CAP_ENABLECOLORPATCHCODE;
public CapWriter<TW_BOOL> CAP_ENABLECOLORPATCHCODE =>
_CAP_ENABLECOLORPATCHCODE ??= new(_twain, (CAP)KDS_CAP.CAP_ENABLECOLORPATCHCODE, 2);
CapWriter<int>? _CAP_ENERGYSTAR;
public CapWriter<int> CAP_ENERGYSTAR =>
_CAP_ENERGYSTAR ??= new(_twain, (CAP)KDS_CAP.CAP_ENERGYSTAR, 2);
CapWriter<TW_BOOL>? _CAP_FEEDERKEEPALIVE;
public CapWriter<TW_BOOL> CAP_FEEDERKEEPALIVE =>
_CAP_FEEDERKEEPALIVE ??= new(_twain, (CAP)KDS_CAP.CAP_FEEDERKEEPALIVE, 2);
CapWriter<ushort>? _CAP_FEEDERMODE;
public CapWriter<ushort> CAP_FEEDERMODE =>
_CAP_FEEDERMODE ??= new(_twain, (CAP)KDS_CAP.CAP_FEEDERMODE, 2);
CapWriter<TW_BOOL>? _CAP_FIXEDDOCUMENTSIZE;
public CapWriter<TW_BOOL> CAP_FIXEDDOCUMENTSIZE =>
_CAP_FIXEDDOCUMENTSIZE ??= new(_twain, (CAP)KDS_CAP.CAP_FIXEDDOCUMENTSIZE, 2);
CapWriter<ushort>? _CAP_FOLDEDCORNER;
public CapWriter<ushort> CAP_FOLDEDCORNER =>
_CAP_FOLDEDCORNER ??= new(_twain, (CAP)KDS_CAP.CAP_FOLDEDCORNER, 2);
CapWriter<ushort>? _CAP_FOLDEDCORNERSENSITIVITY;
public CapWriter<ushort> CAP_FOLDEDCORNERSENSITIVITY =>
_CAP_FOLDEDCORNERSENSITIVITY ??= new(_twain, (CAP)KDS_CAP.CAP_FOLDEDCORNERSENSITIVITY, 2);
CapWriter<TW_BOOL>? _CAP_INDICATORSWARMUP;
public CapWriter<TW_BOOL> CAP_INDICATORSWARMUP =>
_CAP_INDICATORSWARMUP ??= new(_twain, (CAP)KDS_CAP.CAP_INDICATORSWARMUP, 2);
CapWriter<int>? _CAP_MULTIFEEDCOUNT;
public CapWriter<int> CAP_MULTIFEEDCOUNT =>
_CAP_MULTIFEEDCOUNT ??= new(_twain, (CAP)KDS_CAP.CAP_MULTIFEEDCOUNT, 2);
CapWriter<ushort>? _CAP_MULTIFEEDRESPONSE;
public CapWriter<ushort> CAP_MULTIFEEDRESPONSE =>
_CAP_MULTIFEEDRESPONSE ??= new(_twain, (CAP)KDS_CAP.CAP_MULTIFEEDRESPONSE, 2);
CapWriter<TW_STR255>? _CAP_MULTIFEEDSOUND;
public CapWriter<TW_STR255> CAP_MULTIFEEDSOUND =>
_CAP_MULTIFEEDSOUND ??= new(_twain, (CAP)KDS_CAP.CAP_MULTIFEEDSOUND, 2);
CapWriter<TW_BOOL>? _CAP_MULTIFEEDTHICKNESSDETECTION;
public CapWriter<TW_BOOL> CAP_MULTIFEEDTHICKNESSDETECTION =>
_CAP_MULTIFEEDTHICKNESSDETECTION ??= new(_twain, (CAP)KDS_CAP.CAP_MULTIFEEDTHICKNESSDETECTION, 2);
CapWriter<TW_BOOL>? _CAP_NOWAIT;
public CapWriter<TW_BOOL> CAP_NOWAIT =>
_CAP_NOWAIT ??= new(_twain, (CAP)KDS_CAP.CAP_NOWAIT, 2);
CapWriter<TW_FIX32>? _CAP_PAGECOUNT;
public CapWriter<TW_FIX32> CAP_PAGECOUNT =>
_CAP_PAGECOUNT ??= new(_twain, (CAP)KDS_CAP.CAP_PAGECOUNT, 2);
CapWriter<TW_FIX32>? _CAP_PAGESIZELIMIT;
public CapWriter<TW_FIX32> CAP_PAGESIZELIMIT =>
_CAP_PAGESIZELIMIT ??= new(_twain, (CAP)KDS_CAP.CAP_PAGESIZELIMIT, 2);
CapWriter<ushort>? _CAP_PAPERDESTINATION;
public CapWriter<ushort> CAP_PAPERDESTINATION =>
_CAP_PAPERDESTINATION ??= new(_twain, (CAP)KDS_CAP.CAP_PAPERDESTINATION, 2);
CapWriter<ushort>? _CAP_PAPERJAMRESPONSE;
public CapWriter<ushort> CAP_PAPERJAMRESPONSE =>
_CAP_PAPERJAMRESPONSE ??= new(_twain, (CAP)KDS_CAP.CAP_PAPERJAMRESPONSE, 2);
CapWriter<ushort>? _CAP_PAPERSOURCE;
public CapWriter<ushort> CAP_PAPERSOURCE =>
_CAP_PAPERSOURCE ??= new(_twain, (CAP)KDS_CAP.CAP_PAPERSOURCE, 2);
CapWriter<int>? _CAP_PATCHCOUNT;
public CapWriter<int> CAP_PATCHCOUNT =>
_CAP_PATCHCOUNT ??= new(_twain, (CAP)KDS_CAP.CAP_PATCHCOUNT, 2);
CapWriter<TW_BOOL>? _CAP_PATCHHEAD1;
public CapWriter<TW_BOOL> CAP_PATCHHEAD1 =>
_CAP_PATCHHEAD1 ??= new(_twain, (CAP)KDS_CAP.CAP_PATCHHEAD1, 2);
CapWriter<TW_BOOL>? _CAP_PATCHHEAD2;
public CapWriter<TW_BOOL> CAP_PATCHHEAD2 =>
_CAP_PATCHHEAD2 ??= new(_twain, (CAP)KDS_CAP.CAP_PATCHHEAD2, 2);
CapWriter<TW_BOOL>? _CAP_PATCHHEAD3;
public CapWriter<TW_BOOL> CAP_PATCHHEAD3 =>
_CAP_PATCHHEAD3 ??= new(_twain, (CAP)KDS_CAP.CAP_PATCHHEAD3, 2);
CapWriter<TW_BOOL>? _CAP_PATCHHEAD4;
public CapWriter<TW_BOOL> CAP_PATCHHEAD4 =>
_CAP_PATCHHEAD4 ??= new(_twain, (CAP)KDS_CAP.CAP_PATCHHEAD4, 2);
CapWriter<int>? _CAP_POWEROFFTIMEOUT;
public CapWriter<int> CAP_POWEROFFTIMEOUT =>
_CAP_POWEROFFTIMEOUT ??= new(_twain, (CAP)KDS_CAP.CAP_POWEROFFTIMEOUT, 2);
CapWriter<TW_BOOL>? _CAP_POWEROFFTIMEOUTENABLED;
public CapWriter<TW_BOOL> CAP_POWEROFFTIMEOUTENABLED =>
_CAP_POWEROFFTIMEOUTENABLED ??= new(_twain, (CAP)KDS_CAP.CAP_POWEROFFTIMEOUTENABLED, 2);
CapWriter<TW_BOOL>? _CAP_ENHANCEDSEPARATION;
public CapWriter<TW_BOOL> CAP_ENHANCEDSEPARATION =>
_CAP_ENHANCEDSEPARATION ??= new(_twain, (CAP)KDS_CAP.CAP_ENHANCEDSEPARATION, 2);
CapWriter<TW_STR255>? _CAP_PRINTERDATE;
public CapWriter<TW_STR255> CAP_PRINTERDATE =>
_CAP_PRINTERDATE ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERDATE, 2);
CapWriter<ushort>? _CAP_PRINTERDATEDELIMITER;
public CapWriter<ushort> CAP_PRINTERDATEDELIMITER =>
_CAP_PRINTERDATEDELIMITER ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERDATEDELIMITER, 2);
CapWriter<ushort>? _CAP_PRINTERDATEFORMAT;
public CapWriter<ushort> CAP_PRINTERDATEFORMAT =>
_CAP_PRINTERDATEFORMAT ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERDATEFORMAT, 2);
CapWriter<ushort>? _CAP_PRINTERFONT;
public CapWriter<ushort> CAP_PRINTERFONT =>
_CAP_PRINTERFONT ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERFONT, 2);
CapWriter<ushort>? _CAP_PRINTERFONTFORMAT;
public CapWriter<ushort> CAP_PRINTERFONTFORMAT =>
_CAP_PRINTERFONTFORMAT ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERFONTFORMAT, 2);
CapWriter<int>? _CAP_PRINTERFONTRESIZE;
public CapWriter<int> CAP_PRINTERFONTRESIZE =>
_CAP_PRINTERFONTRESIZE ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERFONTRESIZE, 2);
CapWriter<TW_FIX32>? _CAP_PRINTERPOSITION;
public CapWriter<TW_FIX32> CAP_PRINTERPOSITION =>
_CAP_PRINTERPOSITION ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERPOSITION, 2);
CapWriter<TW_STR255>? _CAP_PRINTERTIME;
public CapWriter<TW_STR255> CAP_PRINTERTIME =>
_CAP_PRINTERTIME ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERTIME, 2);
CapWriter<ushort>? _CAP_PRINTERTIMEFORMAT;
public CapWriter<ushort> CAP_PRINTERTIMEFORMAT =>
_CAP_PRINTERTIMEFORMAT ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTERTIMEFORMAT, 2);
CapWriter<TW_BOOL>? _CAP_PRINTONIMAGEFRONT;
public CapWriter<TW_BOOL> CAP_PRINTONIMAGEFRONT =>
_CAP_PRINTONIMAGEFRONT ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTONIMAGEFRONT, 2);
CapWriter<TW_BOOL>? _CAP_PRINTONIMAGEREAR;
public CapWriter<TW_BOOL> CAP_PRINTONIMAGEREAR =>
_CAP_PRINTONIMAGEREAR ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTONIMAGEREAR, 2);
CapWriter<TW_FIX32>? _CAP_PRINTONIMAGEPOSITIONX;
public CapWriter<TW_FIX32> CAP_PRINTONIMAGEPOSITIONX =>
_CAP_PRINTONIMAGEPOSITIONX ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTONIMAGEPOSITIONX, 2);
CapWriter<TW_FIX32>? _CAP_PRINTONIMAGEPOSITIONY;
public CapWriter<TW_FIX32> CAP_PRINTONIMAGEPOSITIONY =>
_CAP_PRINTONIMAGEPOSITIONY ??= new(_twain, (CAP)KDS_CAP.CAP_PRINTONIMAGEPOSITIONY, 2);
CapWriter<TW_BOOL>? _CAP_SIDESDIFFERENT;
public CapWriter<TW_BOOL> CAP_SIDESDIFFERENT =>
_CAP_SIDESDIFFERENT ??= new(_twain, (CAP)KDS_CAP.CAP_SIDESDIFFERENT, 2);
CapWriter<TW_BOOL>? _CAP_SIMULATING;
public CapWriter<TW_BOOL> CAP_SIMULATING =>
_CAP_SIMULATING ??= new(_twain, (CAP)KDS_CAP.CAP_SIMULATING, 2);
CapWriter<ushort>? _CAP_TOGGLEPATCH;
public CapWriter<ushort> CAP_TOGGLEPATCH =>
_CAP_TOGGLEPATCH ??= new(_twain, (CAP)KDS_CAP.CAP_TOGGLEPATCH, 2);
CapWriter<TW_BOOL>? _CAP_TRANSPORTAUTOSTART;
public CapWriter<TW_BOOL> CAP_TRANSPORTAUTOSTART =>
_CAP_TRANSPORTAUTOSTART ??= new(_twain, (CAP)KDS_CAP.CAP_TRANSPORTAUTOSTART, 2);
CapWriter<int>? _CAP_TRANSPORTTIMEOUT;
public CapWriter<int> CAP_TRANSPORTTIMEOUT =>
_CAP_TRANSPORTTIMEOUT ??= new(_twain, (CAP)KDS_CAP.CAP_TRANSPORTTIMEOUT, 2);
CapWriter<ushort>? _CAP_TRANSPORTTIMEOUTRESPONSE;
public CapWriter<ushort> CAP_TRANSPORTTIMEOUTRESPONSE =>
_CAP_TRANSPORTTIMEOUTRESPONSE ??= new(_twain, (CAP)KDS_CAP.CAP_TRANSPORTTIMEOUTRESPONSE, 2);
CapWriter<ushort>? _CAP_ULTRASONICSENSITIVITY;
public CapWriter<ushort> CAP_ULTRASONICSENSITIVITY =>
_CAP_ULTRASONICSENSITIVITY ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSITIVITY, 2);
CapWriter<ushort>? _CAP_ULTRASONICSENSORCENTER;
public CapWriter<ushort> CAP_ULTRASONICSENSORCENTER =>
_CAP_ULTRASONICSENSORCENTER ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSORCENTER, 2);
CapWriter<ushort>? _CAP_ULTRASONICSENSORLEFT;
public CapWriter<ushort> CAP_ULTRASONICSENSORLEFT =>
_CAP_ULTRASONICSENSORLEFT ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSORLEFT, 2);
CapWriter<ushort>? _CAP_ULTRASONICSENSORRIGHT;
public CapWriter<ushort> CAP_ULTRASONICSENSORRIGHT =>
_CAP_ULTRASONICSENSORRIGHT ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSORRIGHT, 2);
CapWriter<ushort>? _CAP_ULTRASONICSENSORLEFTCENTER;
public CapWriter<ushort> CAP_ULTRASONICSENSORLEFTCENTER =>
_CAP_ULTRASONICSENSORLEFTCENTER ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSORLEFTCENTER, 2);
CapWriter<ushort>? _CAP_ULTRASONICSENSORRIGHTCENTER;
public CapWriter<ushort> CAP_ULTRASONICSENSORRIGHTCENTER =>
_CAP_ULTRASONICSENSORRIGHTCENTER ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSORRIGHTCENTER, 2);
CapWriter<TW_FIX32>? _CAP_ULTRASONICSENSORZONEHEIGHT;
public CapWriter<TW_FIX32> CAP_ULTRASONICSENSORZONEHEIGHT =>
_CAP_ULTRASONICSENSORZONEHEIGHT ??= new(_twain, (CAP)KDS_CAP.CAP_ULTRASONICSENSORZONEHEIGHT, 2);
CapWriter<ushort>? _CAP_WINDOWPOSITION;
public CapWriter<ushort> CAP_WINDOWPOSITION =>
_CAP_WINDOWPOSITION ??= new(_twain, (CAP)KDS_CAP.CAP_WINDOWPOSITION, 2);
}

View File

@@ -0,0 +1,72 @@
using NTwain.Data;
using System;
using System.Collections;
using System.Collections.Generic;
namespace NTwain.Caps;
public record ValueContainer<TValue>
{
public TWON ContainerType { get; set; }
public TValue? OneValue { get; set; }
public IList<TValue>? ArrayValue { get; set; }
public EnumValue<TValue>? EnumValue { get; set; }
public RangeValue<TValue>? RangeValue { get; set; }
public IEnumerable<TValue> GetValues()
{
return ContainerType switch
{
TWON.ONEVALUE => ToEnumerable(OneValue),
TWON.ARRAY => ArrayValue ?? [],
TWON.ENUMERATION => EnumValue?.Items ?? [],
TWON.RANGE => RangeValue != null ? GenerateRangeValues(RangeValue) : [],
_ => [],
};
}
private IEnumerable<TValue> ToEnumerable(TValue? value)
{
if (value == null) yield break;
yield return value;
}
private IEnumerable<TValue> GenerateRangeValues(RangeValue<TValue> range)
{
var dynamicType = typeof(DynamicEnumerator<>);
var genericType = dynamicType.MakeGenericType(typeof(TValue));
var de = Activator.CreateInstance(genericType, range.Min, range.Max, range.Step) as IEnumerator;
if (de == null) yield break;
while (de.MoveNext())
{
yield return (TValue)de.Current;
}
}
}
public record EnumValue<TValue>
{
public TValue[] Items { get; set; } = [];
public int CurrentIndex { get; set; }
public int DefaultIndex { get; set; }
}
public record RangeValue<TValue>
{
public TValue Min { get; set; }
public TValue Max { get; set; }
public TValue Step { get; set; }
public TValue DefaultValue;
public TValue CurrentValue;
}

View File

@@ -0,0 +1,48 @@
using System.Collections.Generic;
namespace NTwain.Data;
// dynamic is a cheap hack to sidestep the compiler restrictions if I know TValue is numeric
class DynamicEnumerator<TValue> : IEnumerator<TValue> where TValue : struct
{
private readonly TValue _min;
private readonly TValue _max;
private readonly TValue _step;
private TValue _cur;
bool started = false;
public DynamicEnumerator(TValue min, TValue max, TValue step)
{
_min = min;
_max = max;
_step = step;
_cur = min;
}
public TValue Current => _cur;
object System.Collections.IEnumerator.Current => this.Current;
public void Dispose() { }
public bool MoveNext()
{
if (!started)
{
started = true;
return true;
}
var next = _cur + (dynamic)_step;
if (next == _cur || next < _min || next > _max) return false;
_cur = next;
return true;
}
public void Reset()
{
_cur = _min;
started = false;
}
}

View File

@@ -2590,7 +2590,9 @@ namespace NTwain.Data
ICONID = 962,
DSMID = 461,
DSMCODEID = 63
DSMCODEID = 63,
DONTCARE = 0xffff
}
///// <summary>

View File

@@ -258,7 +258,7 @@ namespace NTwain.Data
/// A more dotnet-friendly representation of <see cref="TW_ENUMERATION"/>.
/// </summary>
/// <typeparam name="TValue"></typeparam>
public class Enumeration<TValue> where TValue : struct
public class Enumeration<TValue>
{
public int CurrentIndex;
@@ -284,58 +284,24 @@ namespace NTwain.Data
if (MinValue is not IConvertible)
throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration.");
return new DynamicEnumerator(MinValue, MaxValue, StepSize);
return new DynamicEnumerator<TValue>(MinValue, MaxValue, StepSize);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable<TValue>)this).GetEnumerator();
}
// dynamic is a cheap hack to sidestep the compiler restrictions if I know TValue is numeric
class DynamicEnumerator : IEnumerator<TValue>
{
private readonly TValue _min;
private readonly TValue _max;
private readonly TValue _step;
private TValue _cur;
bool started = false;
public DynamicEnumerator(TValue min, TValue max, TValue step)
{
_min = min;
_max = max;
_step = step;
_cur = min;
}
public TValue Current => _cur;
object System.Collections.IEnumerator.Current => this.Current;
public void Dispose() { }
public bool MoveNext()
{
if (!started)
{
started = true;
return true;
}
var next = _cur + (dynamic)_step;
if (next == _cur || next < _min || next > _max) return false;
_cur = next;
return true;
}
public void Reset()
{
_cur = _min;
started = false;
}
}
}
/// <summary>
/// A more dotnet-friendly representation of <see cref="TW_RANGE"/> with boxed values.
/// </summary>
public partial class RangeBoxed
{
public object MinValue;
public object MaxValue;
public object StepSize;
public object DefaultValue;
public object CurrentValue;
}
partial struct TW_FIX32 : IEquatable<TW_FIX32>, IConvertible

View File

@@ -84,6 +84,51 @@ namespace NTwain.Data
}
/// <summary>
/// Reads a boxed one value out of a cap. This can only be done once if memory is freed.
/// </summary>
/// <param name="cap"></param>
/// <param name="memMgr"></param>
/// <param name="freeMemory"></param>
/// <returns></returns>
public static object? ReadOneValueBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
if (cap.ConType != TWON.ONEVALUE || cap.hContainer == IntPtr.Zero) return default;
var lockedPtr = memMgr.Lock(cap.hContainer);
try
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (TWPlatform.IsMacOSX)
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE_MACOSX>(lockedPtr);
itemType = (TWTY)onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
else
{
// Crack the container...
var onevalue = MarshalTo<TW_ONEVALUE>(lockedPtr);
itemType = onevalue.ItemType;
lockedPtr += Marshal.SizeOf(onevalue);
}
return ReadTWTYDataBoxed(lockedPtr, itemType, 0);
}
finally
{
if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
if (freeMemory)
{
memMgr.Free(cap.hContainer);
cap.hContainer = IntPtr.Zero;
}
}
}
/// <summary>
/// Reads a one value out of a cap. This can only be done once if memory is freed.
/// </summary>
@@ -130,6 +175,78 @@ namespace NTwain.Data
}
}
public static Enumeration<object> ReadEnumerationBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
Enumeration<object> retVal = new();
if (cap.ConType != TWON.ENUMERATION || cap.hContainer == IntPtr.Zero) return retVal;
var lockedPtr = memMgr.Lock(cap.hContainer);
try
{
TWTY itemType;
int count = 0;
// Mac has a level of indirection and a different structure (ick)...
if (TWPlatform.IsMacOSX)
{
// Crack the container...
var twenumerationmacosx = MarshalTo<TW_ENUMERATION_MACOSX>(lockedPtr);
itemType = (TWTY)twenumerationmacosx.ItemType;
count = (int)twenumerationmacosx.NumItems;
retVal.DefaultIndex = (int)twenumerationmacosx.DefaultIndex;
retVal.CurrentIndex = (int)twenumerationmacosx.CurrentIndex;
lockedPtr += Marshal.SizeOf(twenumerationmacosx);
}
// Windows or the 2.4+ Linux DSM...
else
{
// Crack the container...
var twenumeration = MarshalTo<TW_ENUMERATION>(lockedPtr);
itemType = twenumeration.ItemType;
count = (int)twenumeration.NumItems;
retVal.DefaultIndex = (int)twenumeration.DefaultIndex;
retVal.CurrentIndex = (int)twenumeration.CurrentIndex;
lockedPtr += Marshal.SizeOf(twenumeration);
}
// The -2.3 Linux DSM...
//else if (twain.m_blFound020302Dsm64bit && (twain.m_linuxdsm == TWAIN.LinuxDsm.Is020302Dsm64bit))
//{
// // Crack the container...
// var twenumerationlinux64 = MarshalTo<TW_ENUMERATION_LINUX64>(lockedPtr);
// itemType = twenumerationlinux64.ItemType;
// count = (int)twenumerationlinux64.NumItems;
// retVal.DefaultIndex = (int)twenumerationlinux64.DefaultIndex;
// retVal.CurrentIndex = (int)twenumerationlinux64.CurrentIndex;
// lockedPtr += Marshal.SizeOf(twenumerationlinux64);
//}
// This shouldn't be possible, but what the hey...
//else
//{
// Log.Error("This is serious, you win a cookie for getting here...");
// return retVal;
//}
retVal.Items = new object[count];
for (var i = 0; i < count; i++)
{
retVal.Items[i] = ReadTWTYDataBoxed(lockedPtr, itemType, i);
}
}
finally
{
if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
if (freeMemory)
{
memMgr.Free(cap.hContainer);
cap.hContainer = IntPtr.Zero;
}
}
return retVal;
}
public static Enumeration<TValue> ReadEnumeration<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
{
Enumeration<TValue> retVal = new();
@@ -202,6 +319,53 @@ namespace NTwain.Data
return retVal;
}
public static IList<object> ReadArrayBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
if (cap.ConType != TWON.ARRAY || cap.hContainer == IntPtr.Zero) return Array.Empty<object>();
var lockedPtr = memMgr.Lock(cap.hContainer);
try
{
TWTY itemType;
uint count;
// Mac has a level of indirection and a different structure (ick)...
if (TWPlatform.IsMacOSX)
{
// Crack the container...
var twarraymacosx = MarshalTo<TW_ARRAY_MACOSX>(lockedPtr);
itemType = (TWTY)twarraymacosx.ItemType;
count = twarraymacosx.NumItems;
lockedPtr += Marshal.SizeOf(twarraymacosx);
}
else
{
// Crack the container...
var twarray = MarshalTo<TW_ARRAY>(lockedPtr);
itemType = twarray.ItemType;
count = twarray.NumItems;
lockedPtr += Marshal.SizeOf(twarray);
}
var arr = new object[count];
for (var i = 0; i < count; i++)
{
arr[i] = ReadTWTYDataBoxed(lockedPtr, itemType, i);
}
return arr;
}
finally
{
if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
if (freeMemory)
{
memMgr.Free(cap.hContainer);
cap.hContainer = IntPtr.Zero;
}
}
}
public static IList<TValue> ReadArray<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
{
if (cap.ConType != TWON.ARRAY || cap.hContainer == IntPtr.Zero) return Array.Empty<TValue>();
@@ -249,6 +413,52 @@ namespace NTwain.Data
}
}
public static RangeBoxed ReadRangeBoxed(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true)
{
var retVal = new RangeBoxed();
if (cap.ConType != TWON.RANGE || cap.hContainer == IntPtr.Zero) return retVal;
var lockedPtr = memMgr.Lock(cap.hContainer);
try
{
TWTY itemType;
// Mac has a level of indirection and a different structure (ick)...
if (TWPlatform.IsMacOSX)
{
itemType = (TWTY)Marshal.ReadInt32(lockedPtr);
lockedPtr += 4;
}
else
{
// Windows or the 2.4+ Linux DSM...
itemType = (TWTY)Marshal.ReadInt16(lockedPtr);
lockedPtr += 2;
}
retVal.MinValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.MaxValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.StepSize = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.CurrentValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
retVal.DefaultValue = ReadTWTYDataBoxed(lockedPtr, itemType, 0);
lockedPtr += 4;
return retVal;
}
finally
{
if (lockedPtr != IntPtr.Zero) memMgr.Unlock(cap.hContainer);
if (freeMemory)
{
memMgr.Free(cap.hContainer);
cap.hContainer = IntPtr.Zero;
}
}
}
public static Range<TValue> ReadRange<TValue>(this ref TW_CAPABILITY cap, IMemoryManager memMgr, bool freeMemory = true) where TValue : struct
{
var retVal = new Range<TValue>();
@@ -373,6 +583,64 @@ namespace NTwain.Data
}
/// <summary>
/// Read the pointer content as a boxed value specified by <see cref="TWTY"/>, except <see cref="TWTY.HANDLE"/>.
/// </summary>
/// <param name="intptr">A locked pointer to the data pointer. If data is array this is the 0th item.</param>
/// <param name="type">The twain type.</param>
/// <param name="itemIndex">Index of the item if pointer is array.</param>
/// <returns></returns>
public static object ReadTWTYDataBoxed(this IntPtr intptr, TWTY type, int itemIndex)
{
switch (type)
{
default:
throw new NotSupportedException($"Unsupported item type {type} for reading.");
// TODO: verify if needs to read int32 for small types
case TWTY.HANDLE:
intptr += IntPtr.Size * itemIndex;
return MarshalTo<IntPtr>(intptr);
case TWTY.INT8:
intptr += 1 * itemIndex;
return MarshalTo<sbyte>(intptr);
case TWTY.UINT8:
intptr += 1 * itemIndex;
return MarshalTo<byte>(intptr);
case TWTY.INT16:
intptr += 2 * itemIndex;
return MarshalTo<short>(intptr);
case TWTY.BOOL:
case TWTY.UINT16:
intptr += 2 * itemIndex;
return MarshalTo<ushort>(intptr);
case TWTY.INT32:
intptr += 4 * itemIndex;
return MarshalTo<int>(intptr);
case TWTY.UINT32:
intptr += 4 * itemIndex;
return MarshalTo<uint>(intptr);
case TWTY.FIX32:
intptr += 4 * itemIndex;
return MarshalTo<TW_FIX32>(intptr);
case TWTY.FRAME:
intptr += 16 * itemIndex;
return MarshalTo<TW_FRAME>(intptr);
case TWTY.STR32:
intptr += TW_STR32.Size * itemIndex;
return MarshalTo<TW_STR32>(intptr);
case TWTY.STR64:
intptr += TW_STR64.Size * itemIndex;
return MarshalTo<TW_STR64>(intptr);
case TWTY.STR128:
intptr += TW_STR128.Size * itemIndex;
return MarshalTo<TW_STR128>(intptr);
case TWTY.STR255:
intptr += TW_STR255.Size * itemIndex;
return MarshalTo<TW_STR255>(intptr);
}
}
/// <summary>
/// Read the pointer content as a value specified by <see cref="TWTY"/>, except <see cref="TWTY.HANDLE"/>.
/// </summary>

View File

@@ -1,7 +1,6 @@
using NTwain.Caps;
using NTwain.Data;
using NTwain.Triplets;
using NTwain.Triplets.ControlDATs;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -102,6 +101,46 @@ namespace NTwain
return sts;
}
/// <summary>
/// Gets a CAP's current value as boxed values. This is a simplified version that doesn't require
/// manual reading, but may or may not work.
/// </summary>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapCurrentBoxed(CAP cap, out List<object> value)
{
value = new List<object>();
var sts = GetCapCurrent(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
{
case TWON.ONEVALUE:
var read = twcap.ReadOneValueBoxed(this);
if (read != null) value.Add(read);
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumerationBoxed(this);
if (twenum.Items != null && twenum.CurrentIndex < twenum.Items.Length)
{
value.Add(twenum.Items[twenum.CurrentIndex]);
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRangeBoxed(this).CurrentValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(this);
if (twarr != null && twarr.Count > 0) value.AddRange(twarr);
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <summary>
/// Gets a CAP's raw default value.
/// Caller will need to manually read and free the memory.
@@ -156,6 +195,46 @@ namespace NTwain
return sts;
}
/// <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>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapDefaultBoxed(CAP cap, out List<object> value)
{
value = new List<object>();
var sts = GetCapDefault(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
switch (twcap.ConType)
{
case TWON.ONEVALUE:
var read = twcap.ReadOneValueBoxed(this);
if (read != null) value.Add(read);
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumerationBoxed(this);
if (twenum.Items != null && twenum.DefaultIndex < twenum.Items.Length)
{
value.Add(twenum.Items[twenum.DefaultIndex]);
}
break;
case TWON.RANGE:
value.Add(twcap.ReadRangeBoxed(this).DefaultValue);
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(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.
@@ -176,33 +255,106 @@ namespace NTwain
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="cap"></param>
/// <param name="values"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapValues<TValue>(CAP cap, out IList<TValue> values) where TValue : struct
public STS GetCapValues<TValue>(CAP cap, out ValueContainer<TValue> value) where TValue : struct
{
values = new List<TValue>();
value = new ValueContainer<TValue> { ContainerType = TWON.DONTCARE };
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
value.ContainerType = twcap.ConType;
switch (twcap.ConType)
{
case TWON.ONEVALUE:
values.Add(twcap.ReadOneValue<TValue>(this));
value.OneValue = 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);
if (twenum.Items != null)
{
value.EnumValue = new EnumValue<TValue>
{
CurrentIndex = twenum.CurrentIndex,
DefaultIndex = twenum.DefaultIndex,
Items = twenum.Items
};
}
break;
case TWON.RANGE:
// This can be slow
var twrange = twcap.ReadRange<TValue>(this);
((List<TValue>)values).AddRange(twrange);
var range = twcap.ReadRange<TValue>(this);
value.RangeValue = new RangeValue<TValue>
{
Min = range.MinValue,
Max = range.MaxValue,
Step = range.StepSize,
DefaultValue = range.DefaultValue,
CurrentValue = range.CurrentValue
};
break;
case TWON.ARRAY:
var twarr = twcap.ReadArray<TValue>(this);
if (twarr != null && twarr.Count > 0)
((List<TValue>)values).AddRange(twarr);
if (twarr != null)
{
value.ArrayValue = twarr;
}
break;
default:
twcap.Free(this); break;
}
}
return sts;
}
/// <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>
/// <param name="cap"></param>
/// <param name="value"></param>
/// <returns></returns>
public STS GetCapValuesBoxed(CAP cap, out ValueContainer<object> value)
{
value = new ValueContainer<object> { ContainerType = TWON.DONTCARE };
var sts = GetCapValues(cap, out TW_CAPABILITY twcap);
if (sts.RC == TWRC.SUCCESS)
{
value.ContainerType = twcap.ConType;
switch (twcap.ConType)
{
case TWON.ONEVALUE:
value.OneValue = twcap.ReadOneValueBoxed(this);
break;
case TWON.ENUMERATION:
var twenum = twcap.ReadEnumerationBoxed(this);
if (twenum.Items != null)
{
value.EnumValue = new EnumValue<object>
{
CurrentIndex = twenum.CurrentIndex,
DefaultIndex = twenum.DefaultIndex,
Items = twenum.Items
};
}
break;
case TWON.RANGE:
var range = twcap.ReadRangeBoxed(this);
value.RangeValue = new RangeValue<object>
{
Min = range.MinValue,
Max = range.MaxValue,
Step = range.StepSize,
DefaultValue = range.DefaultValue,
CurrentValue = range.CurrentValue
};
break;
case TWON.ARRAY:
var twarr = twcap.ReadArrayBoxed(this);
if (twarr != null)
{
value.ArrayValue = twarr;
}
break;
default:
twcap.Free(this); break;