「Webのフォームの値を受け取ってPDFを生成したい」という案件があり、Go v1.12に対応してて動作も軽快で日本語フォントでも文字化けやズレがでないタイ製のライブラリを使ってみました。
同じマルチバイト文化圏だから安心
GoのPDFライブラリ、 gopdfはタイのSignin Technologyが開発しているGo用のPDF生成ライブラリです。
同じマルチバイト言圏だからなのか、中華系の仕事が多いからなのかわかりませんが、日本語フォントのカーニングにも対応しているので、ズレたりせずに綺麗に日本語のPDFが生成できます。
gopdf is a simple library for generating PDF document written in Go lang.
Features
- Unicode subfont embedding. (Chinese, Japanese, Korean, etc.)
- Draw line, oval, rect, curve
- Draw image ( jpg, png )
- Password protection
- Font kerning
他のPDFをテンプレートとして使える
gofpdiが組み込まれているので、Wordやエクセル等で出力したPDFファイルをテンプレートファイルとして使えます。差し込み印刷みたいな感じですね。
今回の要件は、今までMS Officeで生成していたPDFの作成業務を自動化したい、けどPDFの見た目は変えたく無いという要件だったので、バッチリでした。
ただ、一旦Macのプレビューで変更したPDFは読み込みエラーが出てしまったので、ベースにするPDFのバージョンとかにある程度制限はあるかもです。
使い方
import
まず、gopdfをインポートします。 v.0.9.2以降を使っていればv1.0.5以上のgofpdiがimportされてテンプレートが使えるようになります。
import(
"github.com/signintech/gopdf"
)
初期化
pdf := gopdf.GoPdf{}
pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
pdf.AddPage()
テンプレート読み込み
テンプレートのPDFを描画してから文字とかを追加するとテンプレートのPDFの上のレイヤーに追加されます。逆に要素を追加後にテンプレートPDFを描画すると、テンプレートのPDFの下のレイヤーに追加されます。
// テンプレートファイルをインポート
tpl := pdf.ImportPage("./template.pdf", 1, "/MediaBox") // 1はページ
// Draw pdf onto page
pdf.UseImportedTemplate(tpl, 0, 0, 595.28, 841.89)// テンプレート構造体, x座標, y座標, 横幅, 高さ
上記の通り、描画時に描画する座標とサイズを選択できるので、縮小して埋め込むとかも可能です。
フォント読み込み
日本語を表示させるためには日本語フォントが必要です。サーバー上の適当なディレクトリにフォントファイルを置いて下記の様に読み込みます。
今回は信頼と実績のIPAフォントを利用しました。
TrueType以外のOpenTypeとかも使えそうですが今回は試していません。また、GoogleフォントのCJKフォントは漢字の字形が変わって、なんか胡散臭くなるので嫌いです。
err := pdf.AddTTFFont("ipagp", "./font/ipagp.ttf")
if err != nil {
panic(err)
}
文字列追加
pdf.SetFont("ipagp", "", 12)//フォント、文字サイズ指定
pdf.SetX(10)//x座標指定
pdf.SetY(10)//y座標指定
pdf.Cell(nil, "ありがとう! signintech & phpdave11")//Rect, String
//行揃え指定する場合
op := gopdf.CellOption{Align: gopdf.Center}//中央寄せ
rect := gopdf.Rect{W: 400, H: 20}
pdf.CellWithOption(&rect, "ありがとう! signintech & phpdave11", op)
byteデータからの画像追加
サンプルでは画像ファイルを読み込んでPDFに追加していたのですが、今回はQRコードを生成して追加したかったので、byteデータを埋め込みました。
QRコード生成についてはまた別に書きます。
ih, err := gopdf.ImageHolderByBytes(generateQRcode())//generateQRcode()は[]byteを返します
pdf.ImageByHolder(ih, 517, 325, nil)//イメージホルダーを使って画像を埋め込み
出力
pdf.Write(w) //このケースではwはhttp.ResponseWriter
上記のコードではブラウザにPDFファイルが表示されます。ちゃんとHTTPヘッダーを出力して上げれば、ダウンロードが始まる感じになります。
フィアルとしてサーバ上に保存したい場合は
pdf.WritePdf("thankyou.pdf")
とします。
今回、初めてGoでPDFいじくってみたのですが、想像以上に簡単にできて楽しかったです。
とはいえ、gopdfで指定していたgofpdiのバージョンが合ってなくてちゃんとPDF読み込めないとか少々地雷踏みましたが、想定内な感じでした。 https://github.com/signintech/gopdf/pull/113
Google Cloud のAppEngineでも動くよ!
今回、開発にはGoogle CloudのAppEngineを使ったのですが、快適に動作して開発楽でした。
AppEngineで使う場合には、app.yamlに
runtime: go112
を書いて、 google.golang.org/appengine を使わない様にしまししょう。 appengine.Main()も使っちゃだめです