Help us understand the problem. What is going on with this article?

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とかだと避けられなかったりしますよね。
そんな時、こちらの記事がお役に立てば幸いです。

kurkuru
Go/React/Ruby/Java/PHP/React Native/IntelliJ IDEA メッセージは twitterのDMから承っております。 https://twitter.com/y_tsubuku
https://ytsubuku.com
kojin-dev
kojin-devは個人開発者による、各々知見を共有するためのコミュニティです。
https://kojin-dev.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした