2
2

More than 3 years have passed since last update.

TwainDotNetによるスキャン

Last updated at Posted at 2020-05-17

1. はじめに

TwainDotNetを使用してC#のWinFormからTWAINでスキャンしました。これを元に、スキャンアプリケーション ITScan - Qiitaを作成しています。

2. 画面

「SelectSource」でスキャナを選択します。
「Scan」でTWAINドライバのダイアログを表示してスキャンします。

20200517.png

3. TwainDotNetの準備

TwainDotNetはnugetで取得できます。バージョン1.0.0を取得しました。
nugetする前にx86でビルドするように変更しないと、警告が表示されます。nugetした後に変更しても大丈夫です。

4. ソース

Form1.cs
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();

20200517-2.png
ソース選択ダイアログ

スキャンを開始します。
最初に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;
            }

20200517-3.png
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;
        }
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2