mirror of
https://github.com/siyuan-note/siyuan
synced 2026-04-21 13:37:52 +00:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
e9cc256964
4 changed files with 107 additions and 75 deletions
|
|
@ -668,7 +668,15 @@ func setFollowSystemLockScreen(c *gin.Context) {
|
|||
func getSysFonts(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
ret.Data = util.LoadSysFonts()
|
||||
fonts := util.LoadSysFonts()
|
||||
|
||||
// TODO: 字重 https://github.com/siyuan-note/siyuan/issues/10313
|
||||
var families []string
|
||||
for _, font := range fonts {
|
||||
families = append(families, font.Family)
|
||||
}
|
||||
families = gulu.Str.RemoveDuplicatedElem(families)
|
||||
ret.Data = families
|
||||
}
|
||||
|
||||
func version(c *gin.Context) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ require (
|
|||
github.com/88250/lute v1.7.7-0.20260419134724-bb68012f231d
|
||||
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1
|
||||
github.com/ClarkThan/ahocorasick v0.0.0-20231011042242-30d1ef1347f4
|
||||
github.com/ConradIrwin/font v0.2.1
|
||||
github.com/ConradIrwin/font v0.2.2-0.20260202161408-44ae4cf5fb22
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/PuerkitoBio/goquery v1.11.0
|
||||
github.com/Xuanwo/go-locale v1.1.3
|
||||
|
|
@ -78,7 +78,6 @@ require (
|
|||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342
|
||||
github.com/xuri/excelize/v2 v2.10.1
|
||||
golang.org/x/image v0.38.0
|
||||
golang.org/x/mobile v0.0.0-20251209145715-2553ed8ce294
|
||||
golang.org/x/mod v0.34.0
|
||||
golang.org/x/net v0.53.0
|
||||
|
|
@ -138,6 +137,7 @@ require (
|
|||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
||||
github.com/go-sw/text-codec v0.0.1 // indirect
|
||||
github.com/goccy/go-json v0.10.6 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
|
|
@ -194,6 +194,7 @@ require (
|
|||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/arch v0.23.0 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/image v0.38.0 // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk
|
|||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/ClarkThan/ahocorasick v0.0.0-20231011042242-30d1ef1347f4 h1:r10k4+Lu1mDpiCKa1liAdGJUhB4BJHHJnMvtoli6Hts=
|
||||
github.com/ClarkThan/ahocorasick v0.0.0-20231011042242-30d1ef1347f4/go.mod h1:a3CzWIqeRxiODAscAIfZ4wbFRXxywBrdCwTENVAWB2g=
|
||||
github.com/ConradIrwin/font v0.2.1 h1:D4tWi7zyRAdVKOtOys5960HnAAfUSRx/syaf+J9JqlI=
|
||||
github.com/ConradIrwin/font v0.2.1/go.mod h1:krTLO7JWu6g8RMxG8sl+T1Hf8W93XQacBKJmqFZ2MFY=
|
||||
github.com/ConradIrwin/font v0.2.2-0.20260202161408-44ae4cf5fb22 h1:xEDrMXxOJsMByKW9Uw2WvwuVhfRd0SN5sOWVR8rYSjc=
|
||||
github.com/ConradIrwin/font v0.2.2-0.20260202161408-44ae4cf5fb22/go.mod h1:5iRYC36M+hBFrRcE25N9/kioASZaqIkAXbgOyfVDCXg=
|
||||
github.com/JalfResi/justext v0.0.0-20221106200834-be571e3e3052 h1:8T2zMbhLBbH9514PIQVHdsGhypMrsB4CxwbldKA9sBA=
|
||||
github.com/JalfResi/justext v0.0.0-20221106200834-be571e3e3052/go.mod h1:0SURuH1rsE8aVWvutuMZghRNrNrYEUzibzJfhEYR8L0=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
|
|
@ -186,6 +186,8 @@ github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3
|
|||
github.com/go-resty/resty/v2 v2.0.0/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-sw/text-codec v0.0.1 h1:H+wnKj5TuvqYlfhMtbc52m1Oe0YnxD7QPzZPBE8QAn8=
|
||||
github.com/go-sw/text-codec v0.0.1/go.mod h1:RTuIwijiCSy7wYLZd3h4RmWHBCD1bERsEST7vqnOzmo=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
|
|
@ -529,7 +531,6 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
|||
golang.org/x/text v0.0.0-20180302201248-b7ef84aaf62a/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
|
|
|
|||
|
|
@ -19,25 +19,24 @@ package util
|
|||
import (
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/ConradIrwin/font/sfnt"
|
||||
"github.com/flopp/go-findfont"
|
||||
"github.com/siyuan-note/logging"
|
||||
ttc "golang.org/x/image/font/sfnt"
|
||||
textUnicode "golang.org/x/text/encoding/unicode"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
var (
|
||||
sysFonts []string
|
||||
sysFonts []*Font
|
||||
sysFontsLock = sync.Mutex{}
|
||||
)
|
||||
|
||||
func LoadSysFonts() (ret []string) {
|
||||
func LoadSysFonts() []*Font {
|
||||
sysFontsLock.Lock()
|
||||
defer sysFontsLock.Unlock()
|
||||
|
||||
|
|
@ -46,21 +45,20 @@ func LoadSysFonts() (ret []string) {
|
|||
}
|
||||
|
||||
start := time.Now()
|
||||
fonts := loadFonts()
|
||||
ret = []string{}
|
||||
for _, font := range fonts {
|
||||
ret = append(ret, font.Family)
|
||||
}
|
||||
ret = gulu.Str.RemoveDuplicatedElem(ret)
|
||||
sort.Strings(ret)
|
||||
sysFonts = ret
|
||||
sysFonts = loadFonts()
|
||||
|
||||
sort.Slice(sysFonts, func(i, j int) bool {
|
||||
return sysFonts[i].DisplayName < sysFonts[j].DisplayName
|
||||
})
|
||||
|
||||
logging.LogInfof("loaded system fonts [%d] in [%dms]", len(sysFonts), time.Since(start).Milliseconds())
|
||||
return
|
||||
return sysFonts
|
||||
}
|
||||
|
||||
type Font struct {
|
||||
Path string
|
||||
Family string
|
||||
Family string `json:"family"` // 对应 CSS font-family
|
||||
Weight int `json:"weight"` // 对应 CSS font-weight
|
||||
DisplayName string `json:"displayName"` // 给人看的名称 (Family + Subfamily)
|
||||
}
|
||||
|
||||
func loadFonts() (ret []*Font) {
|
||||
|
|
@ -68,22 +66,22 @@ func loadFonts() (ret []*Font) {
|
|||
for _, fontPath := range findfont.List() {
|
||||
if strings.HasSuffix(strings.ToLower(fontPath), ".ttc") {
|
||||
families := parseTTCFontFamily(fontPath)
|
||||
for _, family := range families {
|
||||
if existFont(family, ret) {
|
||||
for _, f := range families {
|
||||
if existFont(f, ret) {
|
||||
continue
|
||||
}
|
||||
|
||||
ret = append(ret, &Font{fontPath, family})
|
||||
ret = append(ret, f)
|
||||
//LogInfof("[%s] [%s]", fontPath, family)
|
||||
}
|
||||
} else if strings.HasSuffix(strings.ToLower(fontPath), ".otf") || strings.HasSuffix(strings.ToLower(fontPath), ".ttf") {
|
||||
family := parseTTFFontFamily(fontPath)
|
||||
if "" != family {
|
||||
if existFont(family, ret) {
|
||||
f := parseTTFFontFamily(fontPath)
|
||||
if nil != f {
|
||||
if existFont(f, ret) {
|
||||
continue
|
||||
}
|
||||
|
||||
ret = append(ret, &Font{fontPath, family})
|
||||
ret = append(ret, f)
|
||||
//logging.LogInfof("[%s] [%s]", fontPath, family)
|
||||
}
|
||||
}
|
||||
|
|
@ -91,77 +89,63 @@ func loadFonts() (ret []*Font) {
|
|||
return
|
||||
}
|
||||
|
||||
func existFont(family string, fonts []*Font) bool {
|
||||
func existFont(f *Font, fonts []*Font) bool {
|
||||
for _, font := range fonts {
|
||||
if strings.EqualFold(family, font.Family) {
|
||||
if strings.EqualFold(f.Family, font.Family) && f.Weight == font.Weight {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseTTCFontFamily(fontPath string) (ret []string) {
|
||||
func parseTTCFontFamily(fontPath string) (ret []*Font) {
|
||||
defer logging.Recover()
|
||||
|
||||
data, err := os.ReadFile(fontPath)
|
||||
fontFile, err := os.Open(fontPath)
|
||||
if err != nil {
|
||||
//logging.LogErrorf("read font file [%s] failed: %s", fontPath, err)
|
||||
return
|
||||
}
|
||||
collection, err := ttc.ParseCollection(data)
|
||||
defer fontFile.Close()
|
||||
|
||||
fonts, err := sfnt.ParseCollection(fontFile)
|
||||
if err != nil {
|
||||
//LogErrorf("parse font collection [%s] failed: %s", fontPath, err)
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < collection.NumFonts(); i++ {
|
||||
font, err := collection.Font(i)
|
||||
if err != nil {
|
||||
//LogErrorf("get font [%s] failed: %s", fontPath, err)
|
||||
continue
|
||||
}
|
||||
|
||||
family, _ := font.Name(nil, ttc.NameIDFull)
|
||||
family = strings.TrimSpace(family)
|
||||
if "" != family && !strings.HasPrefix(family, ".") {
|
||||
ret = append(ret, family)
|
||||
}
|
||||
|
||||
family, _ = font.Name(nil, ttc.NameIDFamily)
|
||||
family = strings.TrimSpace(family)
|
||||
if "" != family && !strings.HasPrefix(family, ".") {
|
||||
ret = append(ret, family)
|
||||
}
|
||||
|
||||
family, _ = font.Name(nil, ttc.NameIDTypographicFamily)
|
||||
family = strings.TrimSpace(family)
|
||||
if "" != family && !strings.HasPrefix(family, ".") {
|
||||
ret = append(ret, family)
|
||||
for _, f := range fonts {
|
||||
font := parseFont(f)
|
||||
if nil != font {
|
||||
ret = append(ret, font)
|
||||
}
|
||||
}
|
||||
ret = gulu.Str.RemoveDuplicatedElem(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func parseTTFFontFamily(fontPath string) (ret string) {
|
||||
func parseTTFFontFamily(fontPath string) *Font {
|
||||
defer logging.Recover()
|
||||
|
||||
fontFile, err := os.Open(fontPath)
|
||||
defer fontFile.Close()
|
||||
if err != nil {
|
||||
//LogErrorf("open font file [%s] failed: %s", fontPath, err)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
defer fontFile.Close()
|
||||
|
||||
font, err := sfnt.Parse(fontFile)
|
||||
if err != nil {
|
||||
//LogErrorf("parse font [%s] failed: %s", fontPath, err)
|
||||
return
|
||||
//logging.LogErrorf("parse font [%s] failed: %s", fontFile.Name(), err)
|
||||
return nil
|
||||
}
|
||||
return parseFont(font)
|
||||
}
|
||||
|
||||
func parseFont(font *sfnt.Font) *Font {
|
||||
t, err := font.NameTable()
|
||||
if err != nil {
|
||||
logging.LogErrorf("get font [%s] name table failed: %s", fontPath, err)
|
||||
return
|
||||
//logging.LogErrorf("parse font name table failed: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var family, subfamily string
|
||||
|
|
@ -192,15 +176,53 @@ func parseTTFFontFamily(fontPath string) (ret string) {
|
|||
}
|
||||
}
|
||||
|
||||
//if family != "" && !strings.HasPrefix(family, ".") {
|
||||
// if subfamily != "" && !strings.Contains(subfamily, "<") && !strings.EqualFold(subfamily, "Regular") {
|
||||
// ret = family + "(" + subfamily + ")"
|
||||
// } else {
|
||||
// ret = family
|
||||
// }
|
||||
//}
|
||||
// TODO: 字重加载方案
|
||||
_ = subfamily
|
||||
ret = family
|
||||
return
|
||||
weight := 400
|
||||
os2, err := font.OS2Table()
|
||||
if nil == err {
|
||||
weight = int(os2.USWeightClass)
|
||||
}
|
||||
|
||||
if weight == 400 && subfamily != "" {
|
||||
s := strings.ToLower(subfamily)
|
||||
// 自动匹配 W01-W09
|
||||
for i := 1; i <= 9; i++ {
|
||||
wStr := "w0" + strconv.Itoa(i)
|
||||
if strings.Contains(s, wStr) {
|
||||
weight = i * 100
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 自动匹配标准关键词
|
||||
if weight == 400 { // 如果 W 系列没匹配到
|
||||
switch {
|
||||
case strings.Contains(s, "thin"):
|
||||
weight = 100
|
||||
case strings.Contains(s, "light"):
|
||||
weight = 300
|
||||
case strings.Contains(s, "medium"):
|
||||
weight = 500
|
||||
case strings.Contains(s, "semibold") || strings.Contains(s, "demi"):
|
||||
weight = 600
|
||||
case strings.Contains(s, "bold"):
|
||||
weight = 700
|
||||
case strings.Contains(s, "black") || strings.Contains(s, "heavy"):
|
||||
weight = 900
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if family != "" && !strings.HasPrefix(family, ".") {
|
||||
displayName := family
|
||||
if subfamily != "" && !strings.EqualFold(subfamily, "Regular") {
|
||||
displayName = family + " " + subfamily
|
||||
}
|
||||
|
||||
return &Font{
|
||||
Family: family,
|
||||
Weight: weight,
|
||||
DisplayName: displayName,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue