mirror of
https://github.com/soukoku/ntwain.git
synced 2025-04-05 20:15:42 +08:00
Some more QoL and sample process options.
This commit is contained in:
parent
f58bf3c620
commit
4d8da799c0
67
samples/WinForm32/Form1.Designer.cs
generated
67
samples/WinForm32/Form1.Designer.cs
generated
@ -41,6 +41,9 @@
|
||||
lblState = new System.Windows.Forms.Label();
|
||||
label3 = new System.Windows.Forms.Label();
|
||||
btnOpenDef = new System.Windows.Forms.Button();
|
||||
btnOpenFolder = new System.Windows.Forms.Button();
|
||||
ckSystemDrawing = new System.Windows.Forms.CheckBox();
|
||||
ckBgImageHandling = new System.Windows.Forms.CheckBox();
|
||||
ckShowUI = new System.Windows.Forms.CheckBox();
|
||||
capListView = new System.Windows.Forms.ListView();
|
||||
colCap = new System.Windows.Forms.ColumnHeader();
|
||||
@ -53,7 +56,7 @@
|
||||
btnStart = new System.Windows.Forms.Button();
|
||||
btnShowSettings = new System.Windows.Forms.Button();
|
||||
btnClose = new System.Windows.Forms.Button();
|
||||
ckBgImageHandling = new System.Windows.Forms.CheckBox();
|
||||
ckSaveDisk = new System.Windows.Forms.CheckBox();
|
||||
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
|
||||
splitContainer1.Panel1.SuspendLayout();
|
||||
splitContainer1.Panel2.SuspendLayout();
|
||||
@ -168,6 +171,9 @@
|
||||
//
|
||||
// splitContainer1.Panel2
|
||||
//
|
||||
splitContainer1.Panel2.Controls.Add(ckSaveDisk);
|
||||
splitContainer1.Panel2.Controls.Add(btnOpenFolder);
|
||||
splitContainer1.Panel2.Controls.Add(ckSystemDrawing);
|
||||
splitContainer1.Panel2.Controls.Add(ckBgImageHandling);
|
||||
splitContainer1.Panel2.Controls.Add(ckShowUI);
|
||||
splitContainer1.Panel2.Controls.Add(capListView);
|
||||
@ -209,6 +215,38 @@
|
||||
btnOpenDef.UseVisualStyleBackColor = true;
|
||||
btnOpenDef.Click += btnOpenDef_Click;
|
||||
//
|
||||
// btnOpenFolder
|
||||
//
|
||||
btnOpenFolder.Location = new System.Drawing.Point(512, 106);
|
||||
btnOpenFolder.Name = "btnOpenFolder";
|
||||
btnOpenFolder.Size = new System.Drawing.Size(147, 23);
|
||||
btnOpenFolder.TabIndex = 13;
|
||||
btnOpenFolder.Text = "Open saved folder";
|
||||
btnOpenFolder.UseVisualStyleBackColor = true;
|
||||
btnOpenFolder.Click += btnOpenFolder_Click;
|
||||
//
|
||||
// ckSystemDrawing
|
||||
//
|
||||
ckSystemDrawing.AutoSize = true;
|
||||
ckSystemDrawing.Location = new System.Drawing.Point(512, 58);
|
||||
ckSystemDrawing.Name = "ckSystemDrawing";
|
||||
ckSystemDrawing.Size = new System.Drawing.Size(209, 19);
|
||||
ckSystemDrawing.TabIndex = 11;
|
||||
ckSystemDrawing.Text = "Use System.Drawing to save image";
|
||||
ckSystemDrawing.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ckBgImageHandling
|
||||
//
|
||||
ckBgImageHandling.AutoSize = true;
|
||||
ckBgImageHandling.Checked = true;
|
||||
ckBgImageHandling.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
ckBgImageHandling.Location = new System.Drawing.Point(512, 35);
|
||||
ckBgImageHandling.Name = "ckBgImageHandling";
|
||||
ckBgImageHandling.Size = new System.Drawing.Size(220, 19);
|
||||
ckBgImageHandling.TabIndex = 10;
|
||||
ckBgImageHandling.Text = "Handle image data in another thread";
|
||||
ckBgImageHandling.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ckShowUI
|
||||
//
|
||||
ckShowUI.AutoSize = true;
|
||||
@ -226,10 +264,10 @@
|
||||
capListView.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
capListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { colCap, colType, colCur, colDef, colExtended, colSupport });
|
||||
capListView.FullRowSelect = true;
|
||||
capListView.Location = new System.Drawing.Point(11, 87);
|
||||
capListView.Location = new System.Drawing.Point(11, 135);
|
||||
capListView.MultiSelect = false;
|
||||
capListView.Name = "capListView";
|
||||
capListView.Size = new System.Drawing.Size(771, 462);
|
||||
capListView.Size = new System.Drawing.Size(771, 414);
|
||||
capListView.TabIndex = 8;
|
||||
capListView.UseCompatibleStateImageBehavior = false;
|
||||
capListView.View = System.Windows.Forms.View.Details;
|
||||
@ -267,7 +305,7 @@
|
||||
// label4
|
||||
//
|
||||
label4.AutoSize = true;
|
||||
label4.Location = new System.Drawing.Point(13, 62);
|
||||
label4.Location = new System.Drawing.Point(11, 110);
|
||||
label4.Name = "label4";
|
||||
label4.Size = new System.Drawing.Size(91, 15);
|
||||
label4.TabIndex = 7;
|
||||
@ -303,17 +341,15 @@
|
||||
btnClose.UseVisualStyleBackColor = true;
|
||||
btnClose.Click += btnClose_Click;
|
||||
//
|
||||
// ckBgImageHandling
|
||||
// ckSaveDisk
|
||||
//
|
||||
ckBgImageHandling.AutoSize = true;
|
||||
ckBgImageHandling.Checked = true;
|
||||
ckBgImageHandling.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
ckBgImageHandling.Location = new System.Drawing.Point(512, 35);
|
||||
ckBgImageHandling.Name = "ckBgImageHandling";
|
||||
ckBgImageHandling.Size = new System.Drawing.Size(220, 19);
|
||||
ckBgImageHandling.TabIndex = 10;
|
||||
ckBgImageHandling.Text = "Handle image data in another thread";
|
||||
ckBgImageHandling.UseVisualStyleBackColor = true;
|
||||
ckSaveDisk.AutoSize = true;
|
||||
ckSaveDisk.Location = new System.Drawing.Point(512, 83);
|
||||
ckSaveDisk.Name = "ckSaveDisk";
|
||||
ckSaveDisk.Size = new System.Drawing.Size(88, 19);
|
||||
ckSaveDisk.TabIndex = 12;
|
||||
ckSaveDisk.Text = "Save to disk";
|
||||
ckSaveDisk.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
@ -360,5 +396,8 @@
|
||||
private System.Windows.Forms.ColumnHeader colExtended;
|
||||
private System.Windows.Forms.CheckBox ckShowUI;
|
||||
private System.Windows.Forms.CheckBox ckBgImageHandling;
|
||||
private System.Windows.Forms.CheckBox ckSystemDrawing;
|
||||
private System.Windows.Forms.Button btnOpenFolder;
|
||||
private System.Windows.Forms.CheckBox ckSaveDisk;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -17,10 +18,15 @@ namespace WinFormSample
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
{
|
||||
private TwainAppSession twain;
|
||||
private readonly string saveFolder;
|
||||
TwainAppSession twain;
|
||||
readonly string saveFolder;
|
||||
readonly Stopwatch watch = new();
|
||||
private bool _useThreadForImag;
|
||||
readonly ImageCodecInfo _jpegEncoder;
|
||||
readonly EncoderParameters _jpegParameters;
|
||||
readonly int _jpegQuality = 75;
|
||||
bool _useThreadForImag;
|
||||
bool _useSystemDrawing;
|
||||
bool _saveDisk;
|
||||
|
||||
public Form1()
|
||||
{
|
||||
@ -43,10 +49,15 @@ namespace WinFormSample
|
||||
capListView.SetDoubleBufferedAsNeeded();
|
||||
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
|
||||
|
||||
saveFolder = Path.Combine(Path.GetTempPath(), "ntwain-sample");
|
||||
saveFolder = Path.Combine(Path.GetTempPath(), "ntwain-sample" + Path.DirectorySeparatorChar);
|
||||
Directory.CreateDirectory(saveFolder);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private void Twain_SourceDisabled(TwainAppSession sender, TW_IDENTITY_LEGACY e)
|
||||
@ -137,31 +148,62 @@ namespace WinFormSample
|
||||
|
||||
private void HandleTransferredData(TransferredEventArgs e)
|
||||
{
|
||||
try
|
||||
if (e.Data != null)
|
||||
{
|
||||
// example of using some lib to handle image data
|
||||
var saveFile = Path.Combine(saveFolder, (DateTime.Now.Ticks / 1000).ToString());
|
||||
using (var img = new ImageMagick.MagickImage(e.Data))
|
||||
try
|
||||
{
|
||||
if (img.ColorType == ImageMagick.ColorType.Palette)
|
||||
// example of using some lib to handle image data
|
||||
var saveFile = Path.Combine(saveFolder, (DateTime.Now.Ticks / 1000).ToString());
|
||||
|
||||
if (_useSystemDrawing)
|
||||
{
|
||||
// bw or gray
|
||||
saveFile += ".png";
|
||||
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
|
||||
{
|
||||
// color
|
||||
saveFile += ".jpg";
|
||||
img.Quality = 75;
|
||||
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 = _jpegQuality;
|
||||
}
|
||||
if (_saveDisk) img.Write(saveFile);
|
||||
else img.Write(new NoOpStream(), format);
|
||||
}
|
||||
Debug.WriteLine($"Saved image to {saveFile}");
|
||||
}
|
||||
img.Write(saveFile);
|
||||
Debug.WriteLine($"Saved image to {saveFile}");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
e.Dispose();
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,8 +444,20 @@ namespace WinFormSample
|
||||
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 { }
|
||||
}
|
||||
}
|
||||
}
|
44
samples/WinForm32/NoOpStream.cs
Normal file
44
samples/WinForm32/NoOpStream.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WinFormSample
|
||||
{
|
||||
internal class NoOpStream : Stream
|
||||
{
|
||||
public override bool CanRead => false;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => 0;
|
||||
|
||||
public override long Position { get => 0; set { } }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
|
||||
namespace NTwain.Data
|
||||
{
|
||||
@ -13,7 +14,7 @@ namespace NTwain.Data
|
||||
// so the array max is made with 32 MB. Typical usage should be a lot less.
|
||||
internal static readonly ArrayPool<byte> MemPool = ArrayPool<byte>.Create(32 * 1024 * 1024, 8);
|
||||
|
||||
public BufferedData(int size)
|
||||
internal BufferedData(int size)
|
||||
{
|
||||
_buffer = MemPool.Rent(size);
|
||||
_length = size;
|
||||
@ -27,14 +28,14 @@ namespace NTwain.Data
|
||||
_fromPool = fromPool;
|
||||
}
|
||||
|
||||
bool _disposed;
|
||||
bool _fromPool;
|
||||
|
||||
/// <summary>
|
||||
/// Bytes buffer. This may be bigger than the data size
|
||||
/// and contain invalid data.
|
||||
/// </summary>
|
||||
byte[]? _buffer;
|
||||
public byte[]? Buffer { get; }
|
||||
byte[] _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Actual usable data length in the buffer.
|
||||
@ -45,19 +46,47 @@ namespace NTwain.Data
|
||||
/// As a span of usable data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
public ReadOnlySpan<byte> AsSpan()
|
||||
{
|
||||
if (_buffer != null) return _buffer.AsSpan(0, _length);
|
||||
return Span<byte>.Empty;
|
||||
if (_disposed) throw new ObjectDisposedException(GetType().FullName);
|
||||
return _buffer.AsSpan(0, _length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// As a span of usable data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
public ReadOnlyMemory<byte> AsMemory()
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException(GetType().FullName);
|
||||
return _buffer.AsMemory(0, _length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// As a readonly stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
public Stream AsStream()
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException(GetType().FullName);
|
||||
return new MemoryStream(_buffer, 0, _length, false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_fromPool && _buffer != null)
|
||||
if (_fromPool && _disposed)
|
||||
{
|
||||
MemPool.Return(_buffer);
|
||||
_buffer = null;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator ReadOnlySpan<byte>(BufferedData value) => value.AsSpan();
|
||||
public static implicit operator ReadOnlyMemory<byte>(BufferedData value) => value.AsMemory();
|
||||
public static implicit operator Stream(BufferedData value) => value.AsStream();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ namespace NTwain
|
||||
/// IMPORTANT: Content of this array will not be valid once
|
||||
/// this event arg has been disposed.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<byte> Data => _data == null ? ReadOnlySpan<byte>.Empty : _data.AsSpan();
|
||||
public BufferedData? Data => _data;
|
||||
|
||||
/// <summary>
|
||||
/// The file info if the transfer involved file information.
|
||||
|
Loading…
Reference in New Issue
Block a user