39
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C# の PDF作成用ライブラリ

Last updated at Posted at 2017-12-23

今日はいつもにもまして自分用 Tips.

PDFのドキュメントを作成する必要があって、ライブラリを調査してみた。今の希望は、特定のフォーマットの文章を簡単に作る事。

iTextSharp

ゼロからPDFをがっつりレイアウトして作れる。

にだいたい書いている。サンプル書いてみた。コードは見ての通りで、ゴリゴリに座標を指定して、テキストとかラインとかを置いていく感じ。

using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PDFSample
{
    class Program
    {
        static void Main(string[] args)
        {

            var doc = new Document(PageSize.A4.Rotate());
            var stream = new MemoryStream();
            
            var pw = PdfWriter.GetInstance(doc, stream);

            doc.Open();
            var pdfContentByte = pw.DirectContent;
            var bf = BaseFont.CreateFont(@"c:\windows\fonts\msgothic.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

            // A4 595x842 pt = 210x297  
            
            pdfContentByte.SetFontAndSize(bf, 24);
            ShowTextAligned(pdfContentByte, 20, 561, "Fitness Club Membership");

            DrawLine(pdfContentByte, 2, 551, 840, 551);
            
            pdfContentByte.SetFontAndSize(bf, 11);
            ShowTextAligned(pdfContentByte, 20, 530, "You can enojy Muscle Training and high-quality protein.");

            pdfContentByte.SetFontAndSize(bf, 18);
            ShowTextAligned(pdfContentByte, 20, 480, "Name: Mr.Tsuyoshi Ushio Age: 46");
            ShowTextAligned(pdfContentByte, 20, 457, "Membership: Gold");

            doc.Close();

            using (BinaryWriter w = new BinaryWriter(File.OpenWrite(@"result.pdf"))) {
                w.Write(stream.ToArray());
            }
            Console.WriteLine("See the result.pdf");
        }
        private static void ShowTextAligned(PdfContentByte pdfContentByte, float x, float y, string text, int alignment = Element.ALIGN_LEFT, float rotaion = 0)
        {
            pdfContentByte.BeginText();
            pdfContentByte.ShowTextAligned(alignment, text, x, y, rotaion);
            pdfContentByte.EndText();
        }
        private static void DrawLine(PdfContentByte pdfContentByte, float fromX, float fromY, float toX, float toY)
        {
            pdfContentByte.MoveTo(fromX, fromY);
            pdfContentByte.LineTo(toX, toY);
            pdfContentByte.ClosePathStroke();
        }
    }
}

難しくないけど、相当ゴリゴリ。わからなかったは、PDFの座標をどう考えるか?

このページに解説があった 1pt ≒ 0.352777mm のポイント単位で計算。

A4 の場合、約 595x842 pt ⇔ 210x297 mm

出来た。

2017-12-23_22h43_18.png

感想

めんどい。ざっくりとしたのを作りたいだけなのに、座標の指定とかフォントの指定とか面倒すぎる。ちなみに、私は、あるプロジェクトの検証用になんでもいいからPDFを生成するサンプルを書きたかっただけだ。もっと楽なアプローチはないだろうか?

CommonMark.NET + HtmlRenderer.PdfSharp

そうだ、誰かがレイアウトをしてくれたらいいじゃないの?ということは、MDから、PDFに変換してくれるようなものがあれば最高じゃね?と思って調べたのがこちら。

流石に一発変換では無理だけど、MD -> HTML, HTML -> PDF ならイケるとわかった。

コード

スパイクなので冗長なコードが入っているけど、こいつで、MD-> HTML変換。しかもこのライブラリは昔あったライブラリよりずっと高速らしい。

            var html = CommonMark.CommonMarkConverter.Convert(md);

これで、HTML -> PDF 変換。これは楽すぎる。

           using (MemoryStream ms = new MemoryStream())
            {
                var pdf = TheArtOfDev.HtmlRenderer.PdfSharp.PdfGenerator.GeneratePdf(html, PdfSharp.PageSize.A4);
                pdf.Save(ms);
                result = ms.ToArray();
            }
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MdToPDF
{
    class Program
    {
        static void Main(string[] args)
        {
            var md = @"
# Fitness club membership

## Mr.Tsuyoshi Ushio

You are the member of the muscle fitness.

* Zama branch membership
* Gold membershiop
* Protein service included

## Message from manger

You can enjoy muscle training with great equipments. Grow your muscle!
";
            var byteArray = Encoding.UTF8.GetBytes(md);
            var stream = new MemoryStream(byteArray);

            using (var reader = new System.IO.StreamReader(stream))
            using (var writer = new System.IO.StreamWriter("result.html"))
            {
                CommonMark.CommonMarkConverter.Convert(reader, writer);
            }

            var html = CommonMark.CommonMarkConverter.Convert(md);
            Console.WriteLine(html);
            Console.ReadLine();

            Byte[] result = null;
            using (MemoryStream ms = new MemoryStream())
            {
                var pdf = TheArtOfDev.HtmlRenderer.PdfSharp.PdfGenerator.GeneratePdf(html, PdfSharp.PageSize.A4);
                pdf.Save(ms);
                result = ms.ToArray();
            }
            using (BinaryWriter w = new BinaryWriter(File.OpenWrite(@"result.pdf")))
            {
                w.Write(result);
            }


        }
    }
}

結果

これは楽だ。これでいいんじゃない?

pdf.png

私はサンプルだから、こんなもんでいいけど、ガチだと、例えば、同じMD でも、GitHub みたいなもうちょっとカッコよいレイアウトにしたいとか思いそう。その場合は、wikiに書いてあったけど、HtmlFormatter.csを継承して、好きな部分をオーバーライドしてあげればいいみたい。

まとめ

HTMLに一旦変換してからやると、世界は広がって楽になった! ちなみに、HTMLからPDFのライブラリは、C#ネイティブでなくてよければ、wkhtmltopdfというのがあるらしい。ちなみに、印刷の実行に関しては PrinterSettings クラスで可能っぽい。サンプルがついている。

39
67
4

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
39
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?