2020年9月22日 星期二

如何利用 Go ,在圖片加入文字

參考自Stack Overflow 中 «How to add a simple text label to an image in Go?» 的回覆

要用 Go 在圖片加入文字,首先需要字體。

如果沒有字體,可以參照文中範例,使用 basicfont.Face7x13

然而,basicfont.Face7x13只支援拉丁語系的字元的樣子,如果要用到其他語言,例如顯示こんにちは 你好,還是得使用別的字體。

還好現在有開源的思源黑體可以用,這邊就以思源黑體為例,講一下如何處理

使用到的 package 有3個:

  1. golang.org/x/image/font
  2. golang.org/x/image/font/opentype
  3. golang.org/x/image/font/sfnt

字體的部分,整段程式碼如下

import (
    "io/ioutil"

    "golang.org/x/image/font"
    "golang.org/x/image/font/opentype"
    "golang.org/x/image/font/sfnt"
)

const fontPath = `SourceHanSerifJP-Regular.otf` // 這邊隨意挑了個思源的日文粗體

func loadFont() (fontFace font.Face, err error) {
    fontByte, err := ioutil.ReadFile(fontPath)
    if err != nil {
        return
    }

    f, err := sfnt.Parse(fontByte)
    if err != nil {
        return
    }

    fontFace, err = opentype.NewFace(f, &opentype.FaceOptions{
        Size:    144.00,
        DPI:     10.00,
        Hinting: font.HintingNone | font.HintingVertical | font.HintingFull,
    })

    return
}

備註:這邊先說一下,opentype.FaceOptions的設定其實我還沒搞懂,就目前測試的情況,好像三者都要有填才會顯示文字。

將上面的 function 處理好後,套用«How to add a simple text label to an image in Go?»裡面的範例就會顯示出圖片了

package main

import (
    "image"
    "image/color"
    "image/png"
    "os"
    "io/ioutil"

    "golang.org/x/image/font"
    "golang.org/x/image/font/basicfont"
    "golang.org/x/image/font/opentype"
    "golang.org/x/image/font/sfnt"
    "golang.org/x/image/math/fixed"
)

const fontPath = `SourceHanSerifJP-Regular.otf`

func loadFont() (fontFace font.Face, err error) {
    fontByte, err := ioutil.ReadFile(fontPath)
    if err != nil {
        return
    }

    f, err := sfnt.Parse(fontByte)
    if err != nil {
        return
    }

    fontFace, err = opentype.NewFace(f, &opentype.FaceOptions{
        Size:    144.00,
        DPI:     10.00,
        Hinting: font.HintingNone | font.HintingVertical | font.HintingFull,
    })

    return
}

func addLabel(img *image.RGBA, x, y int, label string) {
    col := color.RGBA{200, 100, 0, 255}
    point := fixed.Point26_6{fixed.Int26_6(x * 64), fixed.Int26_6(y * 64)}

    f, err := loadFont()
    if err != nil {
        f = basicfont.Face7x13
    }

    d := &font.Drawer{
        Dst:  img,
        Src:  image.NewUniform(col),
        Face: f,
        Dot:  point,
    }
    d.DrawString(label)
}

func main() {
    img := image.NewRGBA(image.Rect(0, 0, 300, 100))
    addLabel(img, 20, 30, "こんにちは Go 語言")

    f, err := os.Create("hello-go.png")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    if err := png.Encode(f, img); err != nil {
        panic(err)
    }
}

沒有留言:

張貼留言