如何从 golang 中的 .ttf 文件中获取字体系列名称?

How can I get the font family name from a .ttf file in golang?

我们知道,.ttf(或otf)字体文件的文件名并不总是与字体家族名称相同,例如,如果我将Arial.ttf重命名为abcd.ttf,它的字体家族名称仍然是Arial,那么golang中是否有包或库来解析.ttf并获取该名称?

我试过了freetype,但是好像没有办法搞定

package main

import (
    "fmt"
    "io/ioutil"
    "os"

    "github.com/golang/freetype"
)

func main() {
    homeDir, _ = os.UserHomeDir()
    fontFile := homeDir + "/Downloads/New Folder With Items 5/Arial.ttf"
    fontBytes, err := ioutil.ReadFile(fontFile)
    font, err := freetype.ParseFont(fontBytes)
    if err == nil {
        fmt.Println(font)
    }
}

方法很少*truetype.Font

Name returns the Font's name value for the given NameID

我可以在哪里 NameID


编辑:

原来NameID是一个go常量,表示一个field的TrueType字体属性,我发现NameIDPostscriptName字段的值会作为字体唯一名称,例如,.fcpxml 文件将使用此值作为其字体名称

以下代码片段可以获取.ttf文件的唯一字体名称

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"

    // the original freetype has a bug for utf8: https://github.com/golang/freetype/issues/66
    // "github.com/golang/freetype"

    // so we use this beta one
    "github.com/beta/freetype"
    "github.com/beta/freetype/truetype"
)

// getPostscriptName returns the PostscriptName of a .ttf font file
func getPostscriptName(fontFilePath string) (postscriptName string, err error) {
    postscriptName = ""
    fontBytes, err := ioutil.ReadFile(fontFilePath)
    if err == nil {
        font, err := freetype.ParseFont(fontBytes)
        if err == nil {
            postscriptName = font.Name(truetype.NameIDPostscriptName)
        }
    }
    return postscriptName, err
}

func main() {
    fontFileRelative := "Downloads/New Folder With Items 5/Arial.ttf"
    homeDir, _ := os.UserHomeDir()
    fontFile := filepath.Join(homeDir, fontFileRelative)

    postscriptName, _ := getPostscriptName(fontFile)
    fmt.Println(postscriptName)
}

编辑2:

freetype 不支持 otf 文件,谷歌搜索后,我发现我们可以使用 sfnt 来获取 .ttf.otf 字体文件的所有元数据

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"

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

func main() {
    fontFile := "/path/to/Arial.ttf"
    nameIDs, err := getFntNameIDs(fontFile)
    if err == nil {
        fmt.Println(nameIDs["NameIDPostScript"])
        fmt.Println("-------------------------")
        prettyPrint(nameIDs)
    } else {
        fmt.Println(err)
    }
}

// prettyPrint print map or slice as formatted json
func prettyPrint(v interface{}) (err error) {
    b, err := json.MarshalIndent(v, "", "  ")
    if err == nil {
        fmt.Println(string(b))
    }
    return
}

// getFntNameIDs returns .ttf or .otf font NameIDs
// inspired by https://github.com/wayneashleyberry/sfnt
func getFntNameIDs(fontFile string) (NameIDInfo map[string]string, err error) {

    b, err := ioutil.ReadFile(fontFile)
    if err != nil {
        return NameIDInfo, err
    }

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

    nameIDs := []sfnt.NameID{
        sfnt.NameIDCopyright,
        sfnt.NameIDFamily,
        sfnt.NameIDSubfamily,
        sfnt.NameIDUniqueIdentifier,
        sfnt.NameIDFull,
        sfnt.NameIDVersion,
        sfnt.NameIDPostScript,
        sfnt.NameIDTrademark,
        sfnt.NameIDManufacturer,
        sfnt.NameIDDesigner,
        sfnt.NameIDDescription,
        sfnt.NameIDVendorURL,
        sfnt.NameIDDesignerURL,
        sfnt.NameIDLicense,
        sfnt.NameIDLicenseURL,
        sfnt.NameIDTypographicFamily,
        sfnt.NameIDTypographicSubfamily,
        sfnt.NameIDCompatibleFull,
        sfnt.NameIDSampleText,
        sfnt.NameIDPostScriptCID,
        sfnt.NameIDWWSFamily,
        sfnt.NameIDWWSSubfamily,
        sfnt.NameIDLightBackgroundPalette,
        sfnt.NameIDDarkBackgroundPalette,
        sfnt.NameIDVariationsPostScriptPrefix,
    }

    labels := []string{
        "NameIDCopyright",
        "NameIDFamily",
        "NameIDSubfamily",
        "NameIDUniqueIdentifier",
        "NameIDFull",
        "NameIDVersion",
        "NameIDPostScript",
        "NameIDTrademark",
        "NameIDManufacturer",
        "NameIDDesigner",
        "NameIDDescription",
        "NameIDVendorURL",
        "NameIDDesignerURL",
        "NameIDLicense",
        "NameIDLicenseURL",
        "NameIDTypographicFamily",
        "NameIDTypographicSubfamily",
        "NameIDCompatibleFull",
        "NameIDSampleText",
        "NameIDPostScriptCID",
        "NameIDWWSFamily",
        "NameIDWWSSubfamily",
        "NameIDLightBackgroundPalette",
        "NameIDDarkBackgroundPalette",
        "NameIDVariationsPostScriptPrefix",
    }

    NameIDInfo = map[string]string{}
    for i, nameID := range nameIDs {
        label := labels[i]

        value, err := f.Name(nil, nameID)
        if err != nil {
            NameIDInfo[label] = ""
            continue
        }

        NameIDInfo[label] = value
    }

    return NameIDInfo, err
}

输出

ArialMT
-------------------------
{
  "NameIDCompatibleFull": "",
  "NameIDCopyright": "© 2006 The Monotype Corporation. All Rights Reserved.",
  "NameIDDarkBackgroundPalette": "",
  "NameIDDescription": "",
  "NameIDDesigner": "Monotype Type Drawing Office - Robin Nicholas, Patricia Saunders 1982",
  "NameIDDesignerURL": "",
  "NameIDFamily": "Arial",
  "NameIDFull": "Arial",
  "NameIDLicense": "You may use this font to display and print content as permitted by the license terms for the product in which this font is included. You may only (i) embed this font in content as permitted by the embedding restrictions included in this font; and (ii) temporarily download this font to a printer or other output device to help print content.",
  "NameIDLicenseURL": "",
  "NameIDLightBackgroundPalette": "",
  "NameIDManufacturer": "The Monotype Corporation",
  "NameIDPostScript": "ArialMT",
  "NameIDPostScriptCID": "",
  "NameIDSampleText": "",
  "NameIDSubfamily": "Regular",
  "NameIDTrademark": "Arial is a trademark of The Monotype Corporation in the United States and/or other countries.",
  "NameIDTypographicFamily": "",
  "NameIDTypographicSubfamily": "",
  "NameIDUniqueIdentifier": "Monotype:Arial Regular:Version 5.01 (Microsoft)",
  "NameIDVariationsPostScriptPrefix": "",
  "NameIDVendorURL": "",
  "NameIDVersion": "Version 5.01.2x",
  "NameIDWWSFamily": "",
  "NameIDWWSSubfamily": ""
}

实际上软件会使用 NameIDFamilyNameIDTypographicSubfamily 作为 font 属性,而不是 NameIDPostscriptName.

可以用这个go库读取ttf文件的数据freetype, you just need to provide the font data and it will parse all the data. There is also an article about reading ttf files content manually with javascipt here

编辑:如果您使用 freetype 获取姓氏或其他信息,您可以使用该结构的名称接收函数,它接受一个 NameId,它是 uint16 的别名。 (您可以在名称 ID 代码部分找到有效值 here 的完整 table)

例如,您可以使用以下代码获取字体系列名称:

package main

import (
    "fmt"
    "io/ioutil"

    "github.com/golang/freetype"
)

func main() {
    fontFile := "./font.ttf"
    fontBytes, err := ioutil.ReadFile(fontFile)
    font, err := freetype.ParseFont(fontBytes)
    if err == nil {
        fmt.Println(font.Name(1))
    }
}