#1. はじめに
TwainDotNetを使用してC#のWinFormからTWAINでスキャンしました。これを元に、スキャンアプリケーション ITScan - Qiitaを作成しています。
#2. 画面
「SelectSource」でスキャナを選択します。
「Scan」でTWAINドライバのダイアログを表示してスキャンします。
#3. TwainDotNetの準備
TwainDotNetはnugetで取得できます。バージョン1.0.0を取得しました。
nugetする前にx86でビルドするように変更しないと、警告が表示されます。nugetした後に変更しても大丈夫です。
#4. ソース
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using TwainDotNet;
using TwainDotNet.WinFroms;
namespace TwainDotNetTest1
{
public partial class Form1 : Form
{
private const string SCAN_DIR = @"C:\scan";
private Twain twain = null;
private ScanSettings settings = null;
private Bitmap resultImage = null;
private int scanCount = 1;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
twain = new Twain(new WinFormsWindowMessageHook(this));
twain.TransferImage += twain_TransferImage;
twain.ScanningComplete += twain_ScanningComplete;
settings = new ScanSettings();
settings.ShowTwainUI = true;
}
private void btnSelectSource_Click(object sender, EventArgs e)
{
twain.SelectSource();
}
private void btnScan_Click(object sender, EventArgs e)
{
Enabled = false;
try
{
twain.StartScanning(settings);
}
catch (TwainException ex)
{
Enabled = true;
}
}
private void twain_TransferImage(object sender, TransferImageEventArgs e)
{
resultImage = e.Image;
string filename = String.Format("{0:D6}", scanCount++) + ".png";
string fullname = Path.Combine(SCAN_DIR, filename);
resultImage.Save(fullname, ImageFormat.Png);
resultImage.Dispose();
}
private void twain_ScanningComplete(object sender, ScanningCompleteEventArgs e)
{
Enabled = true;
}
}
}
#5. 解説
WinForm用のTwainオブジェクトを作成し、イベントハンドラをセットします。WPF用もあります。
twain = new Twain(new WinFormsWindowMessageHook(this));
twain.TransferImage += twain_TransferImage;
twain.ScanningComplete += twain_ScanningComplete;
後述のStartScanning()に渡すScanSettingsオブジェクトを作成します。StartScanning()のタイミングでTWAINドライバのダイアログを表示するためにShowTwainUIにtrueを代入します。
settings = new ScanSettings();
settings.ShowTwainUI = true;
ソース選択ダイアログを表示します。
twain.SelectSource();
スキャンを開始します。
最初にFormをdisableにしています。
ShowTwainUIをtrueにしているため、TWAINドライバのダイアログが表示され、スキャンを開始するボタンを押下するとスキャンが開始されます。ShowTwainUIがfalseのままだと、TWAINドライバのダイアログが表示されずにスキャンが開始されます。
他のアプリケーションでTWAINドライバが使用中の場合には、TWAINドライバがエラーダイアログを表示して(TWAINドライバの実装に依存する)、ダイアログを閉じた後に例外が発生します。Twain関連の例外をcatchして握りつぶしています。(全ての例外をcatchしてEnable = trueしたほうがより安全ではありますが)
Enabled = false;
try
{
twain.StartScanning(settings);
}
catch (TwainException ex)
{
Enabled = true;
}
TWAINドライバのダイアログ(Canon DR-G1130)
1画像転送される毎にTransferImageが発生します。ADFスキャナの場合には1画像毎に連続して呼ばれます。ここでは0パディング6桁連番でPNGファイルとして保存しています。無条件上書きなので注意して下さい。
resultImage.Dispose()はTwainDotNetのテストプログラムでは行われていませんが、必要です。これがないと数ページ~十数ページ程度処理した後に、TwainDotNet内のnew Bitmap()で「使用されたパラメータが有効ではありません。」の例外が発生し、連続スキャンが止まります。TwainDotNet側ではDispose()していないのと、TransferImageEventArgsで渡されたBitmapをClone()せずに利用することを考えると、イベントハンドラ内でDispose()しないとメモリリークするからです。
private void twain_TransferImage(object sender, TransferImageEventArgs e)
{
resultImage = e.Image;
string filename = String.Format("{0:D6}", scanCount++) + ".png";
string fullname = Path.Combine(SCAN_DIR, filename);
resultImage.Save(fullname, ImageFormat.Png);
resultImage.Dispose();
}
スキャン完了時にScanningCompleteが発生します。ADFスキャナの場合には、連続したスキャンが完了した時に1回呼ばれます。また、TWAINドライバのダイアログを閉じたときにも呼ばれます。
Formをenableに戻しています。
private void twain_ScanningComplete(object sender, ScanningCompleteEventArgs e)
{
Enabled = true;
}