はじめに
お仕事にてClassic asp
およびASP.NET
で作成された既存アプリケーションをBlazor Server
に作り替える作業をしています。
ラベルプリンターの印刷があるシステムの改修する段階となり、使用している外部モジュールなどもバージョンアップしました。
ただFreeSpire.PDF
のバージョン 10.2.0にしたところ、印刷メソッドが削除されていました。一つ前のバージョン 8.6.0は問題ないため、このバージョンにしています。
小さい文字の印字
ラベルプリンターの印刷なので小さい文字が必要となります。
MSゴシック 6ptの文字を印字すると、Acrobat Reader
では印字した場合は細い線を保ったまま綺麗な文字で印字されるが、FreeSpire.PDF
だと細い線が汚く印字される。もちろんその状態でも問題なく読めるので運用上は困ることはない。綺麗な状態を知っていると残念なところである。
上がAcrobat Reader
による印字、下がFreeSpire.PDF
による印字
ghostscript.net
も試してみましたが、FreeSpire.PDF
と同じ印字状態でした。
フォントを調整することで、そこそこマシになりました。
本題
Acrobat Reader
の代替になるものを考えた時に、Microsoft Edge
でPDF
を表示および印刷が出来ることに気が付きました。
WebView2
コントロールを使用して、PDFファイルを印刷するようにしたいと考えました。その際に印刷ダイアログ画面を出さないサイレント印刷を行う。
Acrobat Reader/Adobe Reader をサーバーにインストールし、ネットワーク経由で使用する方法は原則的に禁止されています。
Acrobat Reader/Adobe Reader のサーバー利用について
印刷プログラムの作成
WebView2
コントロールはWindows Forms
アプリケーション(またはWPF
)のコンテキスト内で動作するように設計されています。
印刷プログラムとして「WebView2PdfPrinter.exe」を作成します。
-
Windows Forms
アプリケーション(またはWPF
)で、WebView2
コントロールを貼り付けます。 - コマンドライン引数または設定ファイルで、印刷に必要なパラメーター(最低でもPDFファイルのパス名とプリンター名)を渡します。
- LoadイベントでPrintPdfメソッドを呼びます。
- ビルドしたexeを実行して、パラメーターのpdfファイルが印刷できることを確認します。
private void frmMain_Load(object sender, EventArgs e)
{
// コマンドライン引数を取得
string[] args = Environment.GetCommandLineArgs();
string pdfPath = args[1];
string printerName = args[2];
int count;
int.TryParse(args[3], out count);
if (count == 0) count = 1;
// 印刷処理
PrintPdf(pdfPath, printerName, count);
}
public void PrintPdf(string pdfPath, string printerName, int count)
{
webView2.Source = new Uri(pdfPath);
webView2.NavigationCompleted += async (sender, e) =>
{
if (e.IsSuccess)
{
CoreWebView2PrintSettings printSettings = webView2.CoreWebView2.Environment.CreatePrintSettings();
printSettings.PrinterName = printerName;
printSettings.Copies = count;
var printStatus = await webView2.CoreWebView2.PrintAsync(printSettings);
}
}
}
PrintSettingsクラス
印刷に必要なパラメーターとして、PrintSettingsクラスをセットして渡します。
パラメーター数が多いのでコマンドラインで渡す場合は最小限とし、多くのパラメーターを活かしたいなら設定ファイルで読み込む方式にします。
DLL化の検討
普通にVisual Studioのテンプレートでクラスライブラリーを作成しても、System.Windows.Forms
名前空間を使用できないんですが、下記の方法でDLL化することが出来ました。
上記サイトに従い、csproj
ファイルをテキストエディタで開いて下記を追加します。
<UseWindowsForms>true</UseWindowsForms>
しかし、Blazor Serverで作成したDLLを参照して使用しようとすると、Blazor Server側にもUseWindowsForms
の設定とNuGetでWebView2の参照が必要になってしまう。
それは嫌だなと思ってやめました。
印刷プログラムの呼び出し
Blazor Serverで印刷プログラムを呼び出して使用します。
今回は例として、「C:¥Tool¥WebView2PdfPrinter」フォルダに、WebView2PdfPrinter.exe
と関連するWebView2
などのモジュールを置きます。
Blazor Serverのサンプルアプリケーションで、カウントボタンをクリックしたら印刷されるようにします。
PDFファイルは「LBL00001.pdf」、プリンター名は「EPSON PX-501A」、部数は「1」を指定します。
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
Task.Run(() => Print());
}
private void Print()
{
string directory = @"C:\Tool\WebView2PdfPrinter\";
string toolFilepath = Path.Combine(directory, "WebView2PdfPrinter.exe");
string pdfPath = Path.Combine(directory, "LBL00001.pdf");
string printerName = "EPSON PX-501A";
int count = 1;
var processStartInfo = new ProcessStartInfo
{
FileName = toolFilepath,
Arguments = $"{pdfPath} \"{printerName}\" {count}",
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false,
};
using (var process = Process.Start(processStartInfo)) {
// タイムアウト5秒を設定してプロセスの完了を待つ
if (!process.WaitForExit(5000))
{
// プロセスを強制終了する
process.Kill();
}
}
}
}
PDFのサイレント印刷
IIS用に「C:\inetpub\wwwroot\print」フォルダに発行し、Webブラウザで「localhost/print」してBlazor Serverのサンプルアプリケーションを動かします。
カウントボタンをクリックするとサイレント印刷されるようになります。
配置の注意点
当初は印刷プログラムを「C:¥Tool¥Printer」フォルダではなく、「C:\inetpub\wwwroot\Printer\WebView2PdfPrinter」フォルダに配置したのですが、ここに配置すると権限の問題なのか印刷が出来なくなります。
調査のために色々試してみたのですがPDF表示がそもそも出来なかったです。
inetpubフォルダ以外なら印刷できるので、とりあえずヨシとしました。
最後に
PDFの編集するライブラリーは多くありますが、印刷までサポートしているのはSpire.PDF
など少ししかありません。ただ無料版のFreeSpire.PDF
のバージョン 10.2.0にしたところ、印刷メソッドが削除されていました。
PDFを印刷するには画像に変換する必要があるからハードルが高いようです。
WebView2を使用することでサーバー上からPDFのサイレント印刷が可能となります。
今回、Process.Startで呼び出す方式にしましたが、常駐プログラムにして特定の場所にファイルが配置されたら印刷するようにしてもいいと思います。