最初に
上記が font.Drawer
を用いて GIF に対しLGTMを付与した例です
まぁこれはこれでアリかなって思っちゃいますが、LGTM が躍動感出て不具合感が否めません。
原因
残像が残るのは Gif クラスの Disposal が原因と考えられる。
Go で設定出来る Disposal Method は3種類あり、
DisposalNone = 0x01
DisposalBackground = 0x02
DisposalPrevious = 0x03
取得元の GIF にはドキュメント通りデフォルトの DisposalNone
が設定されていたので、
DisposalBackground
に変更すれば、残像が残らないのではと考えたが、
DisposalNone
から DisposalBackground
に Disposal を指定し直しても描画崩れは発生していた。
※ Disposal の詳細は以下のページに詳しく解説されています。
http://www.snap-tck.com/room03/c02/cg/cg04_02.html
残像が残ってしまうソースコード
func main() {
f, err := os.Open("hoge.gif")
if err != nil {
panic(err)
}
defer f.Close()
g, err := gif.DecodeAll(f)
if err != nil {
panic(err)
}
for _, img := range g.Image {
if err = addText(img, "LGTM"); err != nil {
panic(err)
}
}
newFile, err := os.Create("edited_hoge.gif")
if err != nil {
return "", err
}
defer newFile.Close()
if err := gif.EncodeAll(newFile, g); err != nil {
return "", err
}
}
// addText は img に対して text を中央下部に描画する
func addText(img *image.Paletted, text string) error {
tt, err := truetype.Parse(gobold.TTF)
if err != nil {
return err
}
d := &font.Drawer{
Dst: img,
Src: image.NewUniform(color.White),
Face: truetype.NewFace(tt, &truetype.Options{
Size:40.0,
}),
Dot: fixed.Point26_6{
fixed.Int26_6(((img.Rect.Dx()/2) - 60) * 64),
fixed.Int26_6((img.Rect.Dy()-20) * 64),
},
}
d.DrawString(text)
return nil
}
解決方法
font.Drawer
を用いるのではなく、
LGTM 文字列のみの画像を動的に作成し、GIF に合成 する方法で残像の問題は解決しました。
残像がないソースコード
func main() {
f, err := os.Open("hoge.gif")
if err != nil {
panic(err)
}
defer f.Close()
g, err := gif.DecodeAll(f)
if err != nil {
panic(err)
}
lgtmImage, err := generateLGTMImage(g.Image[0]);
if err != nil {
panic(err)
}
var images []*image.Paletted
var delays []int
var disposals []byte
for i, img := range g.Image {
logoRectangle := image.Rectangle{image.Point{0, 0}, lgtmImage.Bounds().Size()}
draw.Draw(img, logoRectangle, lgtmImage, image.Point{0, 0}, draw.Over)
images = append(images, img)
delays = append(delays, g.Delay[i])
disposals = append(disposals, gif.DisposalNone)
}
buf := new(bytes.Buffer)
if err = gif.EncodeAll(buf, &gif.GIF{
Image: images,
Delay: delays,
Disposal: disposals,
BackgroundIndex: g.BackgroundIndex,
Config: g.Config,
}); err != nil {
panic(err)
}
return buf.Bytes(), nil
}
func generateLGTMImage(img *image.Paletted) (image.Image, error) {
// gif のサイズに合わせて img を生成
newImg := image.NewRGBA(img.Rect)
tt, err := truetype.Parse(gobold.TTF)
if err != nil {
return nil, err
}
d := &font.Drawer{
Dst: newImg,
Src: image.NewUniform(color.White),
Face: truetype.NewFace(tt, &truetype.Options{
Size:40,
},
),
Dot: fixed.Point26_6{fixed.Int26_6(((newImg.Rect.Dx()/2) - 60) * 64), fixed.Int26_6((newImg.Rect.Dy()-20) * 64)},
}
d.DrawString("LGTM")
return newImg, nil
}
感想
この問題にハマった時に font.Drawer
でどうにかならないか試行錯誤してましたが、
別の方法である「合成」で問題解消出来たのでよかったです。
これで猫 gif で心置きなく LGTM 出来ます!
以下のサイトから使ってもいいですし、自分のオリジナルの LGTM gif でも活用してください。
余談
LGTM Cat は Go + Firestore + Cloud Run で作成してます。
元々は Node.JS + GAE (F1 1台)で運用していたのですが、gif を並べて表示しているのでメモリが足りずによくサーバーが落ちてしまっていました。
その点 Cloud Run は無料枠が多い且つ、メモリも好きなだけ増やせれるので上記の問題を解決出来ました。