Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/image/font/sfnt: cannot parse some Chinese font file #52153

Closed
xiebruce opened this issue Apr 5, 2022 · 10 comments
Closed

x/image/font/sfnt: cannot parse some Chinese font file #52153

xiebruce opened this issue Apr 5, 2022 · 10 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@xiebruce
Copy link

xiebruce commented Apr 5, 2022

What version of Go are you using (go version)?

$ go version
go version go1.18 darwin/amd64

Does this issue reproduce with the latest release?

Yes, the latest release that I can upgrade through brew upgrade go on my Mac is go1.18 darwin/amd64(2022.04.05 07:11, UTC+08).

What operating system and processor architecture are you using (go env)?

I'm using macOS 11.5.1 (20G80), Intel amd64

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/bruce/Library/Caches/go-build"
GOENV="/Users/bruce/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/bruce/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/bruce/go"
GOPRIVATE=""
GOPROXY="https://goproxy.cn,direct"
GOROOT="/usr/local/Cellar/go/1.18/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.18/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.18"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/b8/m8lcy7wx235d02cwqsjphzjm0000gn/T/go-build3559794891=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Parse this Chinese font file: Aa漫语手写体.ttf.zip, returns an error, but parse another Chinese font: 华康金刚黑.zip, succeed.

package main

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

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

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 FntNameIDs(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]
		// the first arg of Name() is buffer
		value, err := f.Name(nil, nameID)
		if err != nil {
			NameIDInfo[label] = ""
			continue
		}

		NameIDInfo[label] = value
	}

	return NameIDInfo, err
}

func main() {
	fontFile := "/Users/bruce/Downloads/Aa漫语手写体.ttf"
	// fontFile = "/Users/bruce/Downloads/华康金刚黑.ttf"

	nameIDInfo, err := FntNameIDs(fontFile)
	if err == nil {
		PrettyPrint(nameIDInfo)
	} else {
		fmt.Println(err)
	}
}

What did you expect to see?

Parse this font Aa漫语手写体.ttf.zip, just as parsing this font: 华康金刚黑.zip, so I can get font info, for example, font family name....
Xnip2022-04-05_19-52-03

What did you see instead?

It prints an error:

sfnt: invalid table tag order

image

Evidence to prove Aa漫语手写体.ttf.zip is a normal font

I can install it, and find it in FontBook(macOS)
Xnip2022-04-05_18-06-13

I can use it in TextEdit(macOS)
Xnip2022-04-05_18-04-53

So I think this font file:Aa漫语手写体.ttf.zip should be able to be parsed correctly.

@cherrymui cherrymui changed the title sfnt cannot parse some Chinese font file, affected/package: golang.org/x/image/font/sfnt x/image/font/sfnt: cannot parse some Chinese font file Apr 5, 2022
@gopherbot gopherbot added this to the Unreleased milestone Apr 5, 2022
@cherrymui
Copy link
Member

cc @nigeltao

@cherrymui cherrymui added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Apr 5, 2022
@xiebruce
Copy link
Author

@cherrymui Hello, may I ask: is there anyone working on this issue and about how long will it take to solve this issue? I'm developing a software and I need to get the font info.

@mengzhuo
Copy link
Contributor

mengzhuo commented May 11, 2022

Could you upload the font file in this issue?

@xiebruce
Copy link
Author

xiebruce commented May 11, 2022

Could you upload the font file in this issue?

Thank you for your help in advance!

Actually I've already uploaded in here, click this link and you can download it
image

@mengzhuo
Copy link
Contributor

I think this is work as intended.

According to the TrueType manual(https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html)

The table directory follows the offset subtable. Entries in the table directory must be sorted in ascending order by tag.

Unfortunately Aa漫语手写体.ttf.zip is corrupted at 1886545264 and here is the tag order of it:

tag= 1146308935 prevTag= 0
tag= 1196643650 prevTag= 1146308935
tag= 1330851634 prevTag= 1196643650
tag= 1668112752 prevTag= 1330851634
tag= 1734439792 prevTag= 1668112752
tag= 1735162214 prevTag= 1734439792
tag= 1751474532 prevTag= 1735162214
tag= 1751672161 prevTag= 1751474532
tag= 1752003704 prevTag= 1751672161
tag= 1819239265 prevTag= 1752003704
tag= 1835104368 prevTag= 1819239265
tag= 1851878757 prevTag= 1835104368
tag= 1886352244 prevTag= 1851878757
tag= 1986553185 prevTag= 1886352244
tag= 1986884728 prevTag= 1986553185
tag= 1886545264 prevTag= 1986884728
    sfnt_test.go:966: <nil> sfnt: invalid table tag order

@xiebruce
Copy link
Author

xiebruce commented May 12, 2022

@mengzhuo I believe what you said is correct, but the point is, both macOS and Windows accept this font, that means the author don't know his font has a little problem(maybe this problem is from the font designing software, not the font designer) and many people are using it, actually there are many other fonts acts like Aa漫语手写体.ttf.zip, that means these kind of fonts are widely accepted, when people using my software, I can't told him/her: your font has a problem, because they will reply: why? I can use it on my Mac/ my Windows laptop/ etc. How can I explain? the developing language that I use has a bug?

@mengzhuo
Copy link
Contributor

mengzhuo commented May 12, 2022

As Parse works as intended so I'm going to close this issue.
It should be proposal procedure add parse with relax option instead of "bug report".


p.s.
You can roll your own module contains "relaxed" of sfnt parsing function by deleting order checks.

	for b, first, prevTag := buf, true, uint32(0); len(b) > 0; b = b[16:] {
		tag := u32(b)
		if first {
			first = false
		} else if tag <= prevTag {
			return nil, 0, false, errInvalidTableTagOrder
		}
		prevTag = tag

https://github.com/golang/image/blob/70e8d0d3baa9a699c3865c753cbfa8ae65bd86ce/font/sfnt/sfnt.go#L798-L805

became

	for b := buf; len(b) > 0; b = b[16:] {
		tag := u32(b)

@xiebruce
Copy link
Author

xiebruce commented May 12, 2022

@mengzhuo

In golang.org/x/image@v0.0.0-20220413100746-70e8d0d3baa9/font/sfnt file, by replacing this
image

to this
image
Problem was solved. Thank you so much!

@toy80
Copy link

toy80 commented Jun 20, 2022

820行这个地方的4字节对齐校验, 有些中文字体也通不过:

		// We ignore the checksums, but "all tables must begin on four byte
		// boundries [sic]".

		if o&3 != 0 {
		 	return nil, 0, false, errInvalidTableOffset
		}

@xiebruce
Copy link
Author

820行这个地方的4字节对齐校验, 有些中文字体也通不过:

		// We ignore the checksums, but "all tables must begin on four byte
		// boundries [sic]".

		if o&3 != 0 {
		 	return nil, 0, false, errInvalidTableOffset
		}

OK, thank you.

@golang golang locked and limited conversation to collaborators Jun 21, 2023
hmmftg added a commit to hmmftg/image that referenced this issue Sep 11, 2023
hmmftg added a commit to hmmftg/image-generator that referenced this issue Sep 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants