LoginSignup
10
9

More than 3 years have passed since last update.

FyneでFineな(文字化けしない✙可搬性あり)アプリを作る方法

Last updated at Posted at 2019-12-12

Abstract

GoでGUIアプリを作れるライブラリFyneで日本語が文字化けしないかつ可搬性あるアプリを作成する方法を見つけたので報告します。

Introduction

FyneはGoでGUIアプリを作れるライブラリです。Fyneの概要や使用法は以下のリンクをご参照ください。
- 公式
- Github
- GoDoc
- GoでGUIを作るFyne というライブラリが楽しそうだよ、というご紹介(@KanikoroRerereさんのQiita記事)

Problem

でも、Fyneで日本語を使用するアプリを作ると文字化けします。原因はバンドルされたフォントが英語圏用のNoto Sansだからです。Githubには環境変数FYNE_FONTを用いた回避策が提示されています。でもこの方法はいまいちです。なぜならこのソースファイルを読むと分かるように、環境変数FYNE_FONTにあるフォントを読み込む方式になっているので実行環境での環境変数設定が必要になるからです。

Solution

こんな可搬性のないアプリが使えるかっ!というわけでもっとましな回避策を探します。要するにバンドルされたフォント(正確に言うとフォントを[]byteで直書きしたソースファイル)に日本語文字が含まれていないのが問題なのだから、そのファイルを差し替えればいいわけです。たぶんこれ、バイナリファイルをGoのコードで直書きしているだけだろうと思って変換プログラムを作成しました。ページの一番下のAppendixを見てください。使用法は

var (
    filenameRegular    = "mplus-1c-Regular.ttf"    //Regular Font TTF; Place it in the same folder
    filenameBold       = "mplus-1c-Bold.ttf"       //Bold
    filenameItalic     = "NotoSans-Italic.ttf"     //Italic
    filenameBoldItalic = "NotoSans-BoldItalic.ttf" //BoldItalic
    filenameMono       = "NotoMono-Regular.ttf"    //Mono
)

のfilenameに使用したいTTFファイルを代入してソースと同じフォルダにおいて走らせるだけです。ここでは例としてRegularとBoldにM+ FONTSを使用させていただいています。TTCしかないフォントの場合、uniteTTCでTTFを作成すれば使用できます。
吐き出されたbundled-fonts.goで***\src\fyne-io\fyne\theme\bundled-fonts.goを置き換えて、go install -i fyne.io/fyneで再インストールします。(ファイルの場所と再インストールのコマンドは環境それぞれです。)この状態でコンパイルして作成された実行ファイルは他のPCでも文字化けしませんでした。なお、正しく新しいbundled-fonts.goがインストールされたかどうかは生成された実行ファイルの容量が増加することで分かります。

Appendix

最後に、今回作成した変換プログラムを置いておきます。TTFによってはTTFが不正だよとかなんとかエラーが出ます。エラーが出ないTTFをしよう使用(適当)。

//Go source to generate custom bundled-fonts.go
//Replace...)\fyne-io\fyne\theme\bundled-fonts.go by the generated file
package main

import (
    "fmt"
    "io/ioutil"
    "strconv"
    "strings"
    "time"
    "unsafe"
)

// func ttf_to_data(filename string) string {
//  x, errx := ioutil.ReadFile(filename)
//  if errx != nil {
//      panic("Read Error in " + filename)
//  }
//  fmt.Println("Reading " + filename)

//  str := "[]byte{"
//  for _, byte1 := range x {
//      str = str + strconv.Itoa(int(byte1)) + ","
//  }
//  return strings.TrimRight(str, ",") + "}"
// }

func ttf_to_data(filename string) string {
    x, errx := ioutil.ReadFile(filename)
    if errx != nil {
        panic("Read Error in " + filename)
    }
    fmt.Println("Reading " + filename + ": length was " + strconv.Itoa(len(x)))

    vec := make([]string, len(x))
    for ix, byte1 := range x {
        vec[ix] = strconv.Itoa(int(byte1))
    }
    //fmt.Println(strings.Join(vec, ","))
    return "[]byte{" + strings.Join(vec, ",") + "}"
}

var (
    filenameRegular    = "mplus-1c-Regular.ttf"    //Regular Font TTF; Place it in the same folder
    filenameBold       = "mplus-1c-Bold.ttf"       //Bold
    filenameItalic     = "NotoSans-Italic.ttf"     //Italic
    filenameBoldItalic = "NotoSans-BoldItalic.ttf" //BoldItalic
    filenameMono       = "NotoMono-Regular.ttf"    //Mono
)

func main() {
    t0 := time.Now()
    str := strings.Join([]string{
        "// **** THIS FILE IS AUTO-GENERATED Custom bundled-fonts.go//\n//Replace (gopath)\\src\\github.com\\fyne-io\\fyne\\theme\\bundled-fonts.go by the generated file//\n\npackage theme\n\nimport \"fyne.io/fyne\"\n\nvar regular = &fyne.StaticResource{\n    StaticName: \"Custom-Regular.ttf\",\n   StaticContent: ",
        ttf_to_data(filenameRegular),
        "}\nvar bold = &fyne.StaticResource{\n  StaticName: \"Custom-Bold.ttf\",\n  StaticContent: ",
        ttf_to_data(filenameBold),
        "}\nvar italic = &fyne.StaticResource{\n    StaticName: \"Custom-Italic.ttf\",\n    StaticContent: ",
        ttf_to_data(filenameItalic),
        "}\nvar bolditalic = &fyne.StaticResource{\n    StaticName: \"Custom-BoldItalic.ttf\",\n    StaticContent: ",
        ttf_to_data(filenameBoldItalic),
        "}\nvar monospace = &fyne.StaticResource{\n StaticName: \"Custom-Mono-Regular.ttf\",\n  StaticContent: ",
        ttf_to_data(filenameMono),
        "}",
    }, "")

    data := *(*[]byte)(unsafe.Pointer(&str))
    errx := ioutil.WriteFile("bundled-fonts.go", data, 0777)
    if errx != nil {
        panic("Write error")
    }

    fmt.Print("Total time was ")
    fmt.Print(time.Since(t0).Minutes())
    fmt.Print(" minutes. ")

}

追記(2019/12/29)

  • M+ FONTSIPA Font(TTF)での動作を確認しています。
  • 投稿直後にFyneが1.2にVer UPされました。同様の作業が再度必要になりはしますが、問題なく動作しています。なんかAndroidに対応したとか...
10
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9