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)
}
}
There are few methods of *truetype.Font
Name returns the Font's name value for the given NameID
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
.
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))
}
}