HTML
Go
PDF
golang

GoでHTMLをPDFに出力する

More than 1 year has passed since last update.

はじめに :airplane_departure:

GoでHTMLからPDF出力する方法をまとめました。

環境構築 :park:

wkhtmltopdfのインストール

wkhtmltopdfというCLIツールをGoから呼ぶことになるので、
まずはこちらをインストールします。

公式Downloadsから、自分の環境にあったものを選択しましょう。

wkhtmltopdf.png

※macの場合は、brew caskでインストール可能が可能です。

brew cask install wkhtmltopdf

Goのライブラリをインストール

今回は、go-wkhtmltopdfを使用します

go get -u github.com/SebastiaanKlippert/go-wkhtmltopdf

ざっくりレシピ :meat_on_bone:

:one: URLから

main.go
package main

import (
    "fmt"
    "log"
    "github.com/SebastiaanKlippert/go-wkhtmltopdf"
)

func main() {
    // Create new PDF generator
    pdfg, err := wkhtmltopdf.NewPDFGenerator()
    if err != nil {
        log.Fatal(err)
    }
    url := "https://google.com/"

    pdfg.AddPage(wkhtmltopdf.NewPage(url))

    // PDF作成
    err = pdfg.Create()
    if err != nil {
        log.Fatal(err)
    }

    // 出力
    err = pdfg.WriteFile("./google.pdf")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("tada!")
}

結果

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f39393837342f31633930373665372d313165322d646464312d646266312d3739306666336538623038652e6a706567.jpg

:two: ファイルから

main.go
package main

import (
    "fmt"
    "log"
    "github.com/SebastiaanKlippert/go-wkhtmltopdf"
)

func main() {
    // Create new PDF generator
    pdfg, err := wkhtmltopdf.NewPDFGenerator()
    if err != nil {
        log.Fatal(err)
    }
    p := "./test.html"

    pdfg.AddPage(wkhtmltopdf.NewPage(p))

    // PDF作成
    err = pdfg.Create()
    if err != nil {
        log.Fatal(err)
    }

    // 出力
    err = pdfg.WriteFile("./test.pdf")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("tada!")
}

:three: HTML文字列から

main.go
package main

import (
    "fmt"
    "log"
    "github.com/SebastiaanKlippert/go-wkhtmltopdf"
    "strings"
)

func main() {
    // Create new PDF generator
    pdfg, err := wkhtmltopdf.NewPDFGenerator()
    if err != nil {
        log.Fatal(err)
    }
    html := `
    <html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    <h1>こんにちは!!!</h1>
    </body>
    </html>`

    pdfg.AddPage(wkhtmltopdf.NewPageReader(strings.NewReader(html)))

    // PDF作成
    err = pdfg.Create()
    if err != nil {
        log.Fatal(err)
    }

    // 出力
    err = pdfg.WriteFile("./test.pdf")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("tada!")
}

結果

test.jpg

:four: 複数のHTML文字列の場合

こちら、複数のHTMLを渡して、ページをうまいこと分けてくれないかなと思ったのですが、
もとのCLIツールの実装的に難しいそうです(標準入力は一つしか受け取れないので、、、)

Unable_to_generate_more_than_one_page_while_reading_different_htmls_·_Issue__7_·_SebastiaanKlippert_go-wkhtmltopdf.png

参考:
https://github.com/SebastiaanKlippert/go-wkhtmltopdf/issues/7#issuecomment-293183363

なので、代替案として ファイルに一度出力してから、そのパスを指定するが良さそうです。

main.go
package main

import (
    "fmt"
    "log"
    "github.com/SebastiaanKlippert/go-wkhtmltopdf"
)

func main() {
    // Create new PDF generator
    pdfg, err := wkhtmltopdf.NewPDFGenerator()
    if err != nil {
        log.Fatal(err)
    }
    tmp1 := "./tmp/tmp1.html"
    tmp2 := "./tmp/tmp2.html"
    tmp3 := "./tmp/tmp3.html"

    pdfg.AddPage(wkhtmltopdf.NewPage(tmp1))
    pdfg.AddPage(wkhtmltopdf.NewPage(tmp2))
    pdfg.AddPage(wkhtmltopdf.NewPage(tmp3))

    // PDF作成
    err = pdfg.Create()
    if err != nil {
        log.Fatal(err)
    }

    // 出力
    err = pdfg.WriteFile("./test.pdf")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("tada!")
}

このようにすると、3ページに分けてpdfを出力してくれます :tada:

おわりに :airplane_arriving:

PDF出力ってレガシーだなと思いつつも、BtoBとかだと避けられなかったりしますよね。
そんな時、こちらの記事がお役に立てば幸いです。