バックエンドサービスで Excel を PDF に変換しようとして、Microsoft.Office.Interop.Excel を使ったことがあるなら、おそらく一度は問題にぶつかったことがあるはずです。
サーバーに Office が入っていない。高負荷時にランダムにクラッシュする。プロセスが終了しない。ローカルでは動くのに、本番環境では安定しない。
本当に必要なのは、もっと予測可能な方法です。
Office に依存せず、レイアウト崩れもなく、サーバーやコンテナ環境でも安定して動作する仕組みです。
では、.NET でそれをクリーンに実現するにはどうすればよいのでしょうか?
従来の方法が抱える問題
C# で Excel を PDF に変換する方法はいくつかありますが、それぞれに明確な欠点があります。
-
Microsoft.Office.Interop.Excelは、サーバーに Office の完全なインストールを必要とします。これは、Microsoft がサーバーサイドでの使用について明確に推奨していない方法です。たとえ動作したとしても、マルチリクエスト環境でシングルスレッドの COM オートメーションが実行されるため、低速で脆弱であり、何か問題が発生するとゾンビプロセスを残す傾向があります。 - iTextSharp のようなライブラリを使った手動レンダリングは、問題を逆転させます。Office への依存はなくなりますが、今度はすべてのセルを手動で読み取り、スタイルを再作成し、結合セルを処理し、レイアウトをゼロから再構築する必要があります。コードは脆弱で、それだけの作業を経ても、出力が元のレイアウトどおりになることは稀です。
つまり、これらの方法は「スケールしない」か「レイアウトを維持できない」か、その両方になりがちです。
本当に必要なもの
本当の課題は、単に Excel を PDF に変換することではなく、Office が存在せず、それでいて書式が正しく保たれなければならないバックエンド環境で、それを確実に実行することです。
実用的なソリューションには、少なくとも以下が必要です。
- Microsoft Office に依存しないこと – クリーンなサーバーや Linux コンテナで実行できる必要があります。
- 正確な出力 – 結合セル、フォント、列幅、印刷レイアウトがすべて保持されること。
- 複雑なファイルの処理 – グラフ、画像、複数シートのブックで問題が発生しないこと。
- シンプルな API – 統合するために、ドキュメントレンダリングロジックを最初から作り直す必要がないこと。
これらを踏まえて、実践的な方法を見ていきましょう。
はじめに(最小限のセットアップ)
この用途で実用的なのが、Spire.XLS for .NET のような専用 Excel ライブラリです。
これは Office に依存せず Excel を処理できるスタンドアロン型のライブラリです。
NuGet からインストールできます。
dotnet add package Spire.XLS
または Package Manager Console:
Install-Package Spire.XLS
コードを書く前に、いくつか押さえておきたいポイントがあります。
- .NET 6 / 7 / 8 および .NET Framework に対応
- Windows / Linux / Docker コンテナで動作
- Microsoft Office のインストール不要
セットアップはこれだけです。では実際に変換してみましょう。
基本例:ワークブック全体を PDF に変換
最もシンプルな変換コードはこちらです。
using Spire.Xls;
class Program
{
static void Main()
{
// Workbook オブジェクトを作成
Workbook workbook = new Workbook();
// Excel ファイルを読み込む
workbook.LoadFromFile("input.xlsx");
// オプション:各シートをページに収める
workbook.ConverterSetting.SheetFitToPage = true;
// PDF として保存
workbook.SaveToFile("output.pdf", FileFormat.PDF);
// リソース解放
workbook.Dispose();
}
}
これが完全な変換処理です。COM オブジェクトも、Office のインストールも、クリーンアップすべき一時ファイルもありません。このアプローチは、バックグラウンドジョブ、スケジュールされたタスク、または API ベースのレポート生成で特に有効です。
このライブラリが自動的に処理するいくつかの点:
- 結合セル — そのまま保持されます
- フォントとセルスタイル — 出力に引き継がれます
- 列幅と行の高さ — リフローや推測はありません
SheetFitToPage = true は、基本的に有効化しておくのがおすすめです。これを設定しないと、横に長いシートが途中で分割されてしまうことがあります。
この時点で、Office 不要かつレイアウト保持可能な Excel → PDF パイプラインが完成しています。
高度な Excel から PDF への変換シナリオ
実際のプロジェクトでは、単純な全体変換だけでは済まないことが多いです。
ここではよくある3つのパターンを紹介します。
特定のワークシートだけを出力
複数シートのうち、特定のシートだけを PDF 化したい場合です。
using Spire.Xls;
class Program
{
static void Main()
{
Workbook workbook = new Workbook();
workbook.LoadFromFile("sample.xlsx");
// 4 番目のシートを取得(0 始まり)
Worksheet sheet = workbook.Worksheets[3];
// 横幅を1ページに収める
sheet.PageSetup.FitToPagesWide = 1;
sheet.PageSetup.FitToPagesTall = 0;
// PDF 出力
sheet.SaveToPdf("output.pdf");
workbook.Dispose();
}
}
複数シートを個別 PDF として出力
各シートを別々の PDF ファイルにしたい場合です。
using Spire.Xls;
using System.IO;
class Program
{
static void Main()
{
// Workbook オブジェクトを作成し、Excel ファイルを読み込み
Workbook workbook = new Workbook();
workbook.LoadFromFile("sample.xlsx");
// 出力ディレクトリを取得(入力ファイルと同じ場所)
string outputDir = Path.GetDirectoryName("sample.xlsx");
// すべてのワークシートを反復処理
for (int i = 0; i < workbook.Worksheets.Count; i++)
{
Worksheet sheet = workbook.Worksheets[i];
// ワークシート名を PDF のファイル名として使用
string fileName = $"{sheet.Name}.pdf";
string outputPath = Path.Combine(outputDir, fileName);
// ワークシートを PDF として保存
sheet.SaveToPdf(outputPath);
System.Console.WriteLine($"エクスポート完了: {sheet.Name} → {fileName}");
}
// リソースを解放
workbook.Dispose();
System.Console.WriteLine("\nすべてのシートを書き出しました。");
}
}
印刷範囲だけを PDF 化
Excel の印刷範囲だけを出力したい場合です。
using Spire.Xls;
class Program
{
static void Main()
{
Workbook workbook = new Workbook();
workbook.LoadFromFile("sample.xlsx");
Worksheet sheet = workbook.Worksheets[0];
// 印刷範囲を指定
sheet.PageSetup.PrintArea = "A2:G12";
// 横幅を1ページに収める
sheet.PageSetup.FitToPagesWide = 1;
sheet.PageSetup.FitToPagesTall = 0;
// PDF 出力
sheet.SaveToPdf("output.pdf");
workbook.Dispose();
}
}
テンプレート帳票などで、不要な補助データを PDF に含めたくない場合に便利です。
ASP.NET Core で PDF を直接返す
実際のバックエンドでは、PDF をディスクに保存したくないケースも多いです。特に Docker やクラウド環境では、ローカルファイルシステムが使えないこともあります。
以下はメモリ上で直接 PDF を返す例です。
using Microsoft.AspNetCore.Mvc;
using Spire.Xls;
[ApiController]
[Route("api/[controller]")]
public class ReportController : ControllerBase
{
[HttpGet("export")]
public IActionResult ExportToPdf()
{
// Excel ワークブックを読み込み
Workbook workbook = new Workbook();
workbook.LoadFromFile("report.xlsx"); // ファイルが正しい場所に存在することを確認
workbook.ConverterSetting.SheetFitToPage = true;
// メモリへ直接変換 — 一時ファイル不要
using var stream = new MemoryStream();
workbook.SaveToStream(stream, FileFormat.PDF);
workbook.Dispose();
// 読み取り前に位置を巻き戻し
stream.Position = 0;
// ファイルダウンロードとして返す
return File(
stream.ToArray(), // 最適化可能(大きなファイルの場合は、ToArray() の代わりにストリームを直接返すことを検討)
"application/pdf",
"report.pdf" // ブラウザでダウンロードをトリガー
);
}
}
ポイント:
-
SaveToStream()によりメモリへ直接出力 -
stream.Position = 0を忘れると空レスポンスになる -
File()の第3引数でダウンロード名を指定可能
Docker / Azure / AWS Lambda のような環境でも扱いやすい構成です。
正確な出力のためのレイアウト制御
複雑な帳票では、デフォルト設定だけではレイアウトが崩れることがあります。
特に重要なのが次の3つです。
ページサイズと向き
using Spire.Xls;
Workbook workbook = new Workbook();
workbook.LoadFromFile("report.xlsx");
Worksheet sheet = workbook.Worksheets[0];
// 用紙サイズと向きを設定
sheet.PageSetup.PaperSize = PaperSizeType.PaperA4;
sheet.PageSetup.Orientation = PageOrientationType.Landscape;
sheet.SaveToPdf("report.pdf");
workbook.Dispose();
余白
// 値はインチ単位
sheet.PageSetup.TopMargin = 0.5;
sheet.PageSetup.BottomMargin = 0.5;
sheet.PageSetup.LeftMargin = 0.5;
sheet.PageSetup.RightMargin = 0.5;
余白を狭くすることで、コンテンツのためのスペースが広がります。特に、幅の広い表を1ページに収めようとしている場合に役立ちます。
拡大縮小設定(重要)
// シートを幅1ページ以内に強制的に収める
sheet.PageSetup.FitToPagesWide = 1;
sheet.PageSetup.FitToPagesTall = 0; // 0 = 垂直方向の制限なし
FitToPagesWide = 1 は、幅の広いシートがページの途中で列分割されるのを防ぐ、最も効果的な単一設定です。FitToPagesTall = 0 に設定すると、コンテンツが必要に応じて垂直方向に拡大できます。すべてを1ページに押し込むことなく、クリーンな単一列レイアウトが得られます。
これらの 3 つの設定は、Excel のページレイアウトタブで印刷前に設定する内容を反映しています。シートがそこで正しく表示されていれば、エクスポートされた PDF でも正しく表示されます。
よくある問題と対処法
フォントが □□□ になる
シナリオ: PDF 出力は Windows では正常に見えるが、CI サーバーやコンテナではテキストが表示されるべき場所に空白のボックスが表示される。
原因: Excel ファイルが、サーバー環境で利用できないフォントを使用しています。ライブラリは欠落しているフォントにフォールバックして、何もレンダリングしません。
修正: 環境に不足しているフォントをインストールするか、ライブラリにカスタムフォントディレクトリを指定します。
// 実行時に Spire.XLS にフォントの場所を伝える
workbook.CustomFontPath = "/usr/share/fonts/custom";
Linux で Windows スタイルのフォントを使用する場合、apt 経由で ttf-mscorefonts-installer をインストールすると、通常、最も一般的なケースが解決されます。
グラフや画像が PDF に表示されない
シナリオ: ワークブックに、エクスポートされた PDF に表示されないグラフや埋め込み画像が含まれている。
原因: グラフのレンダリングには、シートが特定のレンダリングモードで処理される必要があります。デフォルト設定では、埋め込みオブジェクトがスキップされる可能性があります。
修正: ワークシートレベルのメソッドではなく、ワークブックレベルのメソッドで変換していることを確認してください。ワークブックレベルの変換は、グラフを含む完全なレンダリングパスを適用します。
// グラフや画像を含むシートにはこちらを推奨
workbook.ConverterSetting.SheetFitToPage = true;
workbook.SaveToFile("report.pdf", FileFormat.PDF);
Linux / Docker でのレイアウトエラーまたはクラッシュ
シナリオ: ローカルの Windows ではすべて正常に動作するが、Linux コンテナにデプロイした後、DllNotFoundException が発生するか、PDF レイアウトが完全に壊れる。
原因: Spire.XLS は System.Drawing.Common に依存しており、これはさらに libgdiplus を必要とします。これは、デフォルトの .NET Linux ベースイメージに含まれていないネイティブライブラリです。
修正: Dockerfile に以下を追加します。
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libgdiplus \
libc6-dev \
libx11-dev \
&& rm -rf /var/lib/apt/lists/*
これは、Linux コンテナで Spire.XLS を実行するための公式に推奨されているセットアップです。
まとめ
ここまでで、.NET における実用的な Excel → PDF 変換フローが完成しました。Office への依存、脆弱な COM オートメーション、レイアウトをゼロから再構築する必要もありません。これは、バックグラウンドジョブ、API、コンテナ化されたサービスで同様にうまく機能し、単純なエクスポートからより複雑なレポートシナリオまでスケールします。
もし現在、あなたのプロジェクトで Excel → PDF 変換を行っているなら、どんな方法を使っていますか?




