【.NET/C#】PDFファイルを作る【PdfSharp】

ネコニウム研究所

PCを利用したモノづくりに関連する情報や超個人的なナレッジを掲載するブログ

【.NET/C#】PDFファイルを作る【PdfSharp】

2024-7-29 |

.NETでPdfSharpを使ってPDFファイルを作りたい!

概要

今回の記事では、.NETでPdfSharpを使ってPDFファイルを作る手順を掲載する。

仕様書

環境

  • NET 8.0
  • PdfSharp 6.1.1

手順書

NuGetパッケージマネージャーなどからPdfSharpをインストールする。

Install-Package PdfSharp

日本語のフォントを読み込んで、日本語のテキストが含まれるPDFをエクスポートする例。

日本語のフォントは上記URLのIBM Plex Sans JPと源真ゴシックを使わせてもらった。

using PdfSharp.Drawing;
using PdfSharp.Fonts;
using PdfSharp.Pdf;
using System.Runtime.InteropServices;

namespace tests
{
    public class FontResolver : IFontResolver
    {
        public FontResolver() { }

        public byte[] GetFont(string faceName)
        {
            using (var stream = File.OpenRead(faceName))
            {
                var data = new byte[stream.Length];
                stream.Read(data, 0, data.Length);
                return data;
            }
        }

        public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
        {
            switch (familyName)
            {
                case "源真ゴシック":
                    return new FontResolverInfo("GenShinGothic-Regular.ttf", isBold, isItalic);
                case "IBM Plex Sans JP":
                default:
                    return new FontResolverInfo("IBMPlexSansJP-Regular.ttf", isBold, isItalic);

            }
        }
    }

    internal class Program
    {
        static public void ExportPDF1()
        {
            using (var pdf = new PdfDocument())
            {
                // PDFにページを追加
                PdfPage page = pdf.AddPage();
                // ページのサイズを設定
                page.Size = PdfSharp.PageSize.A4;
                // ページの向き
                page.Orientation = PdfSharp.PageOrientation.Portrait;

                // ページから描写に使うクラスをインスタンス化
                var gfx = XGraphics.FromPdfPage(page);

                // FontResolverから文字列描写に使うフォントを作る。フォント、スタイルごとに必要になる
                var fontResolver = new FontResolver();
                GlobalFontSettings.FontResolver = fontResolver;
                var font1Regular = new XFont("IBM Plex Sans JP", 32, XFontStyleEx.Regular);
                var font1Bold = new XFont("IBM Plex Sans JP", 32, XFontStyleEx.Bold);
                var font1Italic = new XFont("IBM Plex Sans JP", 32, XFontStyleEx.Italic);
                var font1BoldItalic = new XFont("IBM Plex Sans JP", 32, XFontStyleEx.BoldItalic);
                var font1Strikeout = new XFont("IBM Plex Sans JP", 32, XFontStyleEx.Strikeout);

                var font2Regular = new XFont("源真ゴシック", 32, XFontStyleEx.Regular);
                var font2Bold = new XFont("源真ゴシック", 32, XFontStyleEx.Bold);
                var font2Italic = new XFont("源真ゴシック", 32, XFontStyleEx.Italic);
                var font2BoldItalic = new XFont("源真ゴシック", 32, XFontStyleEx.BoldItalic);
                var font2Strikeout = new XFont("源真ゴシック", 32, XFontStyleEx.Strikeout);

                double offsetX1 = 20;
                double offsetX2 = page.Width.Value - (offsetX1 * 2);
                double offsetY = 20;
                double lineHeight = 52;

                // 文字列を描写
                gfx.DrawString("PDFテスト", font1Regular, XBrushes.Black, new XRect(offsetX1, offsetY, offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Regular", font1Regular, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 1), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Bold", font1Bold, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 2), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Italic", font1Italic, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 3), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("BoldItalic", font1BoldItalic, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 4), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Strikeout", font1Strikeout, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 5), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Regular", font2Regular, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 6), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Bold", font2Bold, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 7), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Italic", font2Italic, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 8), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("BoldItalic", font2BoldItalic, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 9), offsetX2, lineHeight), XStringFormats.TopLeft);
                gfx.DrawString("Strikeout", font2Strikeout, XBrushes.Black, new XRect(offsetX1, offsetY + (lineHeight * 10), offsetX2, lineHeight), XStringFormats.TopLeft);

                // 線を描写
                gfx.DrawLine(XPens.Black, offsetX1, offsetY + 48, page.Width.Value - offsetX1, offsetY + 48);

                // 線の色と太さを指定して描写
                var pen = new XPen(XColor.FromArgb(0xFFFF00FF), 16);
                gfx.DrawLine(pen, offsetX1, page.Height.Value - offsetY, page.Width.Value - offsetX1, page.Height.Value - offsetY);

                // 矩形を塗りつぶして、その上に文字列を描写
                gfx.DrawRectangle(XBrushes.Black, offsetX1, offsetY + lineHeight * 11, offsetX2, lineHeight);
                gfx.DrawString("Text", font1Bold, XBrushes.White, new XRect(offsetX1, offsetY + (lineHeight * 11), offsetX2, lineHeight), XStringFormats.CenterLeft);

                // PDFを出力
                pdf.Save("test1.pdf");
            }
        }

        static void Main(string[] args)
        {
            ExportPDF1();
        }
    }
}

日本語を含む外部のフォントファイル(ttfとか)を使うにはインターフェイスIFontResolverを継承したクラスを実装して読み込む。

メソッドResolveTypefaceでスタイル(レギュラー、ボールド、イタリックなど)毎に対応したFontResolverInfoを返すようにする。FontResolverInfoのコンストラクターでメソッドGetFontが呼ばれるので第1引数にttfファイルなどのフォントファイルへのパスを渡す。第2引数、第3引数で太字とイタリックのスタイルを1つフォントファイルからエミュレートできる。スタイルによってフォントファイル自体を指定することもできる。

if (isBold)
{
    return new FontResolverInfo("IBMPlexSansJP-Bold.ttf", false, isItalic);
}
else
{
    return new FontResolverInfo("IBMPlexSansJP-Regular.ttf", false, isItalic);
}

文字列の描写はページに対応したXGraphicsのメソッドDrawStringを使う。XRectでテキストエリアを指定して、XStringFormatsで文字列の配置方法を指定する感じ。XStringFormats.TopLeftだと左上寄せ、XStringFormats.CenterpLeftだと中央左寄せ、垂直、水平の順で位置を指定する感じ。

PdfPage page = pdf.AddPage();
var gfx = XGraphics.FromPdfPage(page);

var fontResolver = new FontResolver();
GlobalFontSettings.FontResolver = fontResolver;
var font = new XFont(
    "IBM Plex Sans JP", // FontResolverの中でフォントの判定に使われる文字列
    32, // フォントサイズ
    XFontStyleEx.Regular // フォントのスタイル
);

gfx.DrawString(
    "PDFテスト", // 描写したい文字列
    font, // 描写に使うXFont
    XBrushes.Black, // フォントの色(XBrushe)
    new XRect(
        24, // テキストエリアの始点のX座標
        32, // Y座標
        200, // 幅
        96 // 高さ
    ),
    XStringFormats.TopLeft // テキストエイアの中での文字列の位置
);

矩形の描写はメソッドDrawRectangleを使う。

gfx.DrawRectangle(
    XBrushes.Black, // 矩形の色(XBrushe)
    24, // 矩形の始点のX座標(XRectと同じ感じ)
    32, // Y座標
    200, // 幅
    96 // 高さ

線の描写にはメソッドDrawLineを使う。

gfx.DrawLine(
    XPens.Black, // 線の色(XPen)
    64, // 線の始点のX座標
    32, // 線の始点のY座標
    256, // 線の終点のX座標
    128 // 線の終点のY座標
);

線の色や太さを指定したい場合はXPenをインスタンス化して使う。

var pen = new XPen(
    XColor.FromArgb(0xFFFF00FF), // ARGBで色を指定
    16 // 線の太さ
);

まとめ(感想文)

簡単なPDFなら簡単に作れちゃう感じ。