GoでHTMLをPDFに出力する

## はじめに :airplane_departure:  
GoでHTMLからPDF出力する方法をまとめました。

## 環境構築 :park: 
### wkhtmltopdfのインストール
[wkhtmltopdf](https://wkhtmltopdf.org)というCLIツールをGoから呼ぶことになるので、
まずはこちらをインストールします。

[公式](https://wkhtmltopdf.org)の[Downloads](https://wkhtmltopdf.org/downloads.html)から、自分の環境にあったものを選択しましょう。

<img width="1440" alt="wkhtmltopdf.png" src="https://qiita-image-store.s3.amazonaws.com/0/99874/a9b7e552-3595-2614-28b2-f2b85ead897b.png">

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

```bash
brew cask install wkhtmltopdf
```

### Goのライブラリをインストール
今回は、[go-wkhtmltopdf](https://github.com/SebastiaanKlippert/go-wkhtmltopdf)を使用します

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

## ざっくりレシピ :meat_on_bone: 
### :one: URLから
```go: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](https://qiita-image-store.s3.amazonaws.com/0/99874/7a12f864-e7fb-f504-a517-dc9deb5d810b.jpeg)


### :two: ファイルから
```go: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文字列から
```go: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](https://qiita-image-store.s3.amazonaws.com/0/99874/df24fbf8-d80e-72c5-9385-67f5b67008cb.jpeg)



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

<img width="775" alt="Unable_to_generate_more_than_one_page_while_reading_different_htmls_·_Issue__7_·_SebastiaanKlippert_go-wkhtmltopdf.png" src="https://qiita-image-store.s3.amazonaws.com/0/99874/4b881aff-7162-494a-bafb-af6c5ab6e0fe.png">



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


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

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