Zenn
Nexta Tech Blog
👻

【C# Excel 帳票】COM操作からClosedXML/NPOI+LibreOfficeに代替した話

に公開

はじめに

生産管理システム SmartF(Windows Forms版)では、Microsoft ExcelのCOM操作を使って各帳票のExcelテンプレート(.xlsx)からPDFを出力しています。

この処理をBlazorベースのWebアプリケーションSmartFへ移植するにあたり、Officeライセンスや技術的制約を考慮した見直しが必要となりました。

この記事では、私が初めてCOM操作に触れたときの経験から、ClosedXML(断念) → NPOI → LibreOffice という技術移行を記録としてまとめます。

背景と技術的制約

Windows Forms 版での構成
あらかじめ作成されたExcelテンプレート(.xlsx)に、アプリケーションからデータを差し込み、
そのままExcelのCOM機能 PrintOutEx を使って、仮想プリンタ(Microsoft Print to PDF)経由でPDFを生成していました。

問題なさそうだが…
この方法はあくまで ローカルのクライアント端末上での利用を前提としていたため、全クライアント端末にOfficeがインストールされていれば特に問題は発生しませんでした。
しかし、Webアプリケーション化(Blazor化)するにあたって課題が発生しました。

サーバー利用におけるライセンス問題

Blazor版 SmartFでは、帳票の出力処理はサーバー側でExcelファイルを生成・PDF化し、それをクライアントに配布する構成になります。

このとき、もしCOM操作を使って帳票を出力しようとすると、Blazorサーバー上でMicrosoft Officeをインストールし、Excelを操作する必要があるということになります。

ここで発生するライセンスの問題

  • クライアントにMicrosoft Officeがインストールされている保障がない
  • しかし、サーバーがOfficeを使ってPDF帳票を出力 → クライアントに配布

この構成は、クライアントがOfficeライセンスを持っていないのに、間接的にOfficeを“使っている”構図になります。
これはMicrosoft Officeライセンスの商用利用の制限に抵触する可能性があり、構成としてNGと判断しました。

代替手段の選定:ClosedXMLとNPOI

そこで検討を始めたのが、Microsoft Officeを必要とせず、サーバー上でも動作するExcel操作ライブラリです。

選定にあたって重視した条件は以下の通りです

  • 無償かつ商用ライセンスで利用可能(MITまたはApacheなど)
  • MicrosoftOffice, Excelのインストール不要
  • .xlsx テンプレートの読み込み・書き込みに対応

その中で有力となったのが、ClosedXMLNPOIでした。

ClosedXMLの採用と限界

メリット

  • 軽量で動作が早い
  • APIがシンプルで読みやすい
    • 学習コストが低い

想定外の制約
SmartFでは、QRコードやバーコードを挿入する位置をテンプレート内のShape(図形)でマークしておき、そこに画像を差し込む構成となっています。

しかし、ClosedXMLはShapeオブジェクトの読み取りに非対応だったため、目印の位置を特定できず、テンプレートからの帳票作成が困難になりました。

この制限が致命的だったため、ClosedXMLでの帳票出力は断念することに。

NPOIへの移行

メリット

  • Shapeオブジェクトを含むテンプレートを解析できる
  • セルのスタイルや構造の細かい制御が可能

試してみた感想

  • APIはやや複雑で、ドキュメントも少なく学習コストが高い
  • JavaのPOIについての情報は多いが、POIにはNPOIに存在しないオブジェクトもあり参考程度..
  • QRやバーコード画像の挿入も、目印のShapeから座標を取得して対応可能
    • COMでは読み取れるが、NPOIだと読み取れないShapeもある..
    • NPOIで読み取れるShapeへ置換するアプリを作成して対応

結果として、ClosedXMLでは実現できなかったShapeの座標取得が、NPOIで可能になったため、帳票出力処理に据えることができました。

PDF変換:LibreOffice連携によるサーバーサイド変換

NPOIでExcelテンプレートへのデータ埋め込みまでは完了しましたが、PDF出力に対応していないため、別途PDF化手段が必要です。
ここで採用したのが、LibreOfficeをサーバー上でヘッドレス起動し、CLIからPDFに変換する方法です。

サンプル

soffice --headless --convert-to pdf 〇〇帳票.xlsx --outdir 出力フォルダ

※ 出力フォルダは指定できますが、出力ファイル名の指定はできませんでした。上記だとエクセルファイル名がそのままPDFファイル名となり、出力フォルダ\〇〇帳票.pdfという出力結果になります。

出力ファイル名を制御したい場合は、変換後にファイルを移動・リネームする処理を追加することで実現できます。

メリット

  • Microsoft Office製品をインストールする必要がない
  • 無償で利用可能なオープンソース
  • --headless モードにより、GUI環境が不要
  • プロセス実行であること
    • アプリに組み込まずに使えるので、独立性が高い
    • たとえばLibreOffice側がクラッシュしても、アプリのメモリ空間には影響しない

この構成により、サーバーにはMicrosoft Officeをインストールする必要がなく、Officeライセンスリスクを排除しながら、テンプレートベースのPDF帳票出力を実現することができました。

おわりに

私自身、帳票作成の経験がなく、実は入社直後でのタスクということもあって、SmartFのコードも帳票テンプレートも見たことがない状態からのスタートでした。

初めてWindows Forms版 SmartF で"COM操作"を見たときは「これだけできるものが他にあるのか」と感じました。
その中で ClosedXML → NPOI → LibreOffice と試行錯誤し、最終的には 無償・Office非依存で帳票出力ができたという話でした。

Nexta Tech Blog
Nexta Tech Blog

Discussion

ログインするとコメントできます