GO言語で画像に日本語を描画する方法を調べました。
同様の記事は見つけられなかったので投稿しておきます。
結論
以下のように日本語キャラクタを含む外部フォントファイルを読み込むことで、日本語を描画できました。
ftBinary, err := ioutil.ReadFile("Koruri-Bold.ttf")
ft, err := truetype.Parse(ftBinary)
なぜ日本語が描画できない?
日本語を描画したいと思い、下記記事を参考にさせていただき、画像に日本語を描画するソースを大雑把に作成しました。
しかし、おなじみの文字化けが発生しました。
文字化けソース全文
package main
import (
"bytes"
"fmt"
"image"
"image/png"
"os"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"golang.org/x/image/font/gofont/gobold"
"golang.org/x/image/math/fixed"
)
func main() {
// フォントの読み込み
ft, err := truetype.Parse(gobold.TTF)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
opt := truetype.Options{
Size: 90,
DPI: 0,
Hinting: 0,
GlyphCacheEntries: 0,
SubPixelsX: 0,
SubPixelsY: 0,
}
imageWidth := 100
imageHeight := 100
textTopMargin := 90
text := "あ"
img := image.NewRGBA(image.Rect(0, 0, imageWidth, imageHeight))
face := truetype.NewFace(ft, &opt)
dr := &font.Drawer{
Dst: img,
Src: image.Black,
Face: face,
Dot: fixed.Point26_6{},
}
dr.Dot.X = (fixed.I(imageWidth) - dr.MeasureString(text)) / 2
dr.Dot.Y = fixed.I(textTopMargin)
dr.DrawString(text)
buf := &bytes.Buffer{}
err = png.Encode(buf, img)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
file, err := os.Create(`test.png`)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer file.Close()
file.Write(buf.Bytes())
}
truetype.Parse(gobold.TTF)
はなにをやっているのか
フォントを読み込む truetype.Parse(gobold.TTF)
は何をやっているのかソースを覗きました。
gobold.TTFより抜粋
// generated by go run gen.go; DO NOT EDIT
// Package gobold provides the "Go Bold" TrueType font
// from the Go font family. It is a proportional-width, sans-serif font.
//
// See https://blog.golang.org/go-fonts for details.
package gobold
// TTF is the data for the "Go Bold" TrueType font.
var TTF = []byte{
0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60, 0x4f, 0x53, 0x2f, 0x32,
// 以下略
コメントよりGo Bold True Type フォント
のバイナリデータ配列
がgobold.TTF
に登録されていることがわかりました。
コメントに記載のThe Go Blog - Go fontsを確認すると
Go fonts
はWGL4キャラクタセット
とのことで、日本語は含まれていません。
そのため対応する文字がないので文字化けしていると推測されます。
日本語キャラクタを含む外部フォントを読み込めば文字化けしない
冒頭に記載したように、外部フォントファイルを読み込めば文字化けせず日本語が描画できました。
日本語フォントには Koruri を利用させてもらいました。
(あらかじめダウンロードし、GOバイナリと同じ場所に配置しています。)
ftBinary, err := ioutil.ReadFile("Koruri-Bold.ttf")
ft, err := truetype.Parse(ftBinary)
日本語が描画できた画像
ソース全文
:nihongook.go
package main
import (
"bytes"
"fmt"
"image"
"image/png"
"os"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font"
"golang.org/x/image/font/gofont/gobold"
"golang.org/x/image/math/fixed"
)
func main() {
// フォントファイルを読み込み
ftBinary, err := ioutil.ReadFile("Koruri-Bold.ttf")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
ft, err := truetype.Parse(ftBinary)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
opt := truetype.Options{
Size: 90,
DPI: 0,
Hinting: 0,
GlyphCacheEntries: 0,
SubPixelsX: 0,
SubPixelsY: 0,
}
imageWidth := 100
imageHeight := 100
textTopMargin := 90
text := "あ"
img := image.NewRGBA(image.Rect(0, 0, imageWidth, imageHeight))
face := truetype.NewFace(ft, &opt)
dr := &font.Drawer{
Dst: img,
Src: image.Black,
Face: face,
Dot: fixed.Point26_6{},
}
dr.Dot.X = (fixed.I(imageWidth) - dr.MeasureString(text)) / 2
dr.Dot.Y = fixed.I(textTopMargin)
dr.DrawString(text)
buf := &bytes.Buffer{}
err = png.Encode(buf, img)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
file, err := os.Create(`test.png`)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer file.Close()
file.Write(buf.Bytes())
}