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

huangapple go评论79阅读模式
英文:

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返回给定NameID的字体名称值

我在哪里可以找到NameID


编辑:

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

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

package main

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

	// 原始的freetype对utf8有一个bug:https://github.com/golang/freetype/issues/66
	// "github.com/golang/freetype"

	// 所以我们使用这个beta版本
	"github.com/beta/freetype"
	"github.com/beta/freetype/truetype"
)

// getPostscriptName返回.ttf字体文件的PostscriptName
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将map或slice格式化为json
func prettyPrint(v interface{}) (err error) {
	b, err := json.MarshalIndent(v, "", "  ")
	if err == nil {
		fmt.Println(string(b))
	}
	return
}

// getFntNameIDs返回.ttf或.otf字体的NameIDs
// 受启发于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

英文:

As we know, a .ttf(or otf) font file's file name is not always the same with the font family name, for example, if I rename Arial.ttf to abcd.ttf, it's font family name is still Arial, so is there a package or library in golang to parse .ttf and get that name?

I've tried freetype, but it seems no method can get it

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)
	}
}

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

There are few methods of *truetype.Font
> Name returns the Font's name value for the given NameID

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


Edit:

It turns out that NameID is a go constant that represents a field of the TrueType font attributes, I found that the value of NameIDPostscriptName field will be used as font unique name, for example, a .fcpxml file will use this value as it's font name

The following snippet can get the unique font name of a .ttf file

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)
}

Edit2:

freetype not supporting otf file, after googling, I found we can use sfnt to get all the metas of a .ttf or an .otf font file

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
}

Output

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": ""
}

And actually softwares will use NameIDFamily and NameIDTypographicSubfamily as the font attribute, not NameIDPostscriptName.

答案1

得分: 1

可以使用这个Go库freetype来读取ttf文件的数据,只需要提供字体数据,它就会解析所有的数据。还有一篇关于使用JavaScript手动读取ttf文件内容的文章在这里

编辑:如果你正在使用freetype获取字体族名称或其他信息,你可以使用结构体的Name接收函数,它接受一个NameId,它是uint16的别名。(你可以在这里找到有效值的完整表格here,在名称ID代码部分)

例如,你可以使用以下代码获取字体族名称:

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))
	}
}
英文:

It is possible to read the data of a ttf file with this go library 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.

Edit: If you are using freetype to get the family name or other information, you can use the Name reciever function of the struct, it accepts a NameId which is an alias for uint16. (You can find the complete table of the valid value here in the name id codes section)

for example, you can get the font family name by using the following code:

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))
}
}

huangapple
  • 本文由 发表于 2022年1月28日 18:25:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/70892173.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定