mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 08:46:55 +08:00
1 parent
12aaada982
commit
7a23dcc6dd
10 files changed
+574
-77
No files matched your search
@@ -16,6 +16,7 @@ package font
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -23,6 +24,8 @@ import (
|
||||
)
|
||||
|
||||
// Face 字体文件中的字体名称与零起始索引,不依赖文件名
|
||||
// Family和Style为排版族,MenuFamily和MenuStyle为兼容四款式的菜单名称
|
||||
// FamilyKey区分兼容族、厂商和版本,未知时为空;Bold和Italic表示字体固有样式
|
||||
type Face struct {
|
||||
Index int `json:"index"`
|
||||
FullName string `json:"fullName"`
|
||||
@@ -30,6 +33,11 @@ type Face struct {
|
||||
Style string `json:"style"`
|
||||
PostScriptName string `json:"postscriptName"`
|
||||
Names []string `json:"names"`
|
||||
MenuFamily string `json:"menuFamily"`
|
||||
MenuStyle string `json:"menuStyle"`
|
||||
FamilyKey string `json:"familyKey"`
|
||||
Bold bool `json:"bold"`
|
||||
Italic bool `json:"italic"`
|
||||
}
|
||||
|
||||
// FaceInfo 从名称表读取字体信息
|
||||
@@ -68,7 +76,40 @@ func faceInfoLanguage(data []byte, index int, platform, language uint16) Face {
|
||||
}
|
||||
return name(ids...)
|
||||
}
|
||||
return Face{Index: index, FullName: localized(4, 6, 16, 1), Family: localized(16, 1), Style: localized(17, 2), PostScriptName: name(6), Names: fontNamesFromValues(records, values)}
|
||||
key := ""
|
||||
if family, version := name(1), name(5); family != "" && version != "" {
|
||||
key = fmt.Sprintf("%x", sha256.Sum256([]byte(strings.Join([]string{family, version, name(8)}, "\x00"))))
|
||||
}
|
||||
family, style := localized(1), localized(2)
|
||||
if family == "" {
|
||||
family = localized(16, 4, 6)
|
||||
}
|
||||
if style == "" {
|
||||
style = localized(17)
|
||||
}
|
||||
return Face{Index: index, FullName: localized(4, 6, 16, 1), Family: localized(16, 1), Style: localized(17, 2), PostScriptName: name(6), Names: fontNamesFromValues(records, values), MenuFamily: family, MenuStyle: style, FamilyKey: key}
|
||||
}
|
||||
|
||||
// TableFaceInfo 读取名称及字体固有款式,名称键不随显示语言变化
|
||||
// 入参: tables 字体表, index 集合索引, platform 平台标识, language 语言标识
|
||||
// 返回: Face 字体信息
|
||||
func TableFaceInfo(tables map[string][]byte, index int, platform, language uint16) Face {
|
||||
face := faceInfoLanguage(tables["name"], index, platform, language)
|
||||
key := face.FamilyKey
|
||||
if head := tables["head"]; len(head) >= 46 {
|
||||
key += string(head[4:8])
|
||||
style := binary.BigEndian.Uint16(head[44:])
|
||||
face.Bold, face.Italic = style&1 != 0, style&2 != 0
|
||||
}
|
||||
if os2 := tables["OS/2"]; len(os2) >= 64 {
|
||||
key += string(os2[58:62])
|
||||
style := binary.BigEndian.Uint16(os2[62:])
|
||||
face.Bold, face.Italic = style&32 != 0, style&1 != 0 || style&512 != 0
|
||||
}
|
||||
if face.FamilyKey != "" {
|
||||
face.FamilyKey = fmt.Sprintf("%x", sha256.Sum256([]byte(key)))
|
||||
}
|
||||
return face
|
||||
}
|
||||
|
||||
// FileCount 校验字体或集合头并读取字体数量
|
||||
@@ -114,7 +155,7 @@ func ReadLocalizedFaces(data []byte, platform, language uint16) ([]Face, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
face := faceInfoLanguage(tables["name"], index, platform, language)
|
||||
face := TableFaceInfo(tables, index, platform, language)
|
||||
if face.FullName == "" {
|
||||
return nil, fmt.Errorf("font %d has no usable name", index)
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func fontNameValues(data []byte) ([]fontNameRecord, map[[4]uint16]string) {
|
||||
values := make(map[[4]uint16]string)
|
||||
for _, record := range records {
|
||||
switch record.Name {
|
||||
case 1, 2, 4, 6, 16, 17:
|
||||
case 1, 2, 4, 5, 6, 8, 16, 17:
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
+65
-1
@@ -757,6 +757,13 @@ func (s *Session) Details() DocumentDetails {
|
||||
}
|
||||
info.SignatureCount = len(info.Signatures)
|
||||
if fonts, err := s.Renderer.DeclaredFontInfos(); err == nil {
|
||||
for index := range fonts {
|
||||
if fonts[index].Embedded {
|
||||
if face, err := s.Reader.FontFace(fonts[index].ID, 3, 0x0804); err == nil {
|
||||
fonts[index].MatchedFace = face
|
||||
}
|
||||
}
|
||||
}
|
||||
info.Fonts = fonts
|
||||
info.FontCount = len(fonts)
|
||||
}
|
||||
@@ -3172,7 +3179,23 @@ func (e *businessEngine) fontFaces(args []platformValue) (any, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (ofdgo.FontFile{Data: data}).Faces()
|
||||
return (ofdgo.FontFile{Data: data}).LocalizedFaces(3, 0x0804)
|
||||
}
|
||||
|
||||
// fontMenu 返回按来源隔离的字体族索引及所需款式候选
|
||||
// 入参: args 字体信息、来源及可选目标款式的JSON
|
||||
// 返回: any 分组和款式索引, error 参数错误
|
||||
func (e *businessEngine) fontMenu(args []platformValue) (any, error) {
|
||||
var request struct {
|
||||
Faces []ofdgo.FontFace `json:"faces"`
|
||||
Sources []string `json:"sources"`
|
||||
Bold bool `json:"bold"`
|
||||
Italic bool `json:"italic"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(args[0].String()), &request); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{"groups": ofdgo.FontFamilyIndexes(request.Faces, request.Sources), "index": ofdgo.FontStyleIndex(request.Faces, request.Bold, request.Italic)}, nil
|
||||
}
|
||||
|
||||
// fontPreferenceOrder 按字体族偏好排列编辑字体候选索引
|
||||
@@ -4969,6 +4992,45 @@ func (e *businessEngine) formatText(args []platformValue) (any, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// styleTextFonts 预检并原子导入各款式字体,批量替换文字字体及粗斜体
|
||||
// 入参: args 页面索引、完整路径、款式映射JSON、字体数据集合及重排标记
|
||||
// 返回: any 文档信息, error 字体或编辑错误
|
||||
func (e *businessEngine) styleTextFonts(args []platformValue) (any, error) {
|
||||
return e.changeObjects(func() error {
|
||||
paths, err := e.editorTargetPaths(e.stringsFromJS(args[1]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var changes []ofdgo.TextFontChange
|
||||
if err := json.Unmarshal([]byte(args[2].Get("changes").String()), &changes); err != nil {
|
||||
return err
|
||||
}
|
||||
fonts := make(map[string]string)
|
||||
input := args[2].Get("fonts")
|
||||
for index := 0; index < input.Length(); index++ {
|
||||
entry := input.Index(index)
|
||||
data, err := e.bytesFromJS(entry.Get("data"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.checkFontGlyphs(data, entry.Get("text").String()); err != nil {
|
||||
return err
|
||||
}
|
||||
id, err := e.currentEditor.AddFont(FontFile{Data: data}, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fonts[entry.Get("key").String()] = id
|
||||
}
|
||||
for index := range changes {
|
||||
if id, ok := fonts[changes[index].To.Font]; ok {
|
||||
changes[index].To.Font = id
|
||||
}
|
||||
}
|
||||
return e.currentEditor.StyleTargetsFonts(args[0].Int(), paths, changes, args[2].Get("reflow").Bool())
|
||||
})
|
||||
}
|
||||
|
||||
// layoutTexts 批量修改段落增量,未指定的选项沿用各对象原值
|
||||
// 入参: args 页面索引、完整路径数组和段落JSON
|
||||
// 返回: any 文档信息, error 校验或提交错误
|
||||
@@ -8029,6 +8091,7 @@ func (e *businessEngine) businessCommands() map[string]func([]platformValue) (an
|
||||
"ofdgoMatchFontFiles": e.matchFontFiles,
|
||||
"ofdgoChangeFontBinding": e.changeFontBinding,
|
||||
"ofdgoFontFaces": e.fontFaces,
|
||||
"ofdgoFontMenu": e.fontMenu,
|
||||
"ofdgoFontFace": e.fontFace,
|
||||
"ofdgoCreateDocument": e.createDocument,
|
||||
"ofdgoImportImages": e.importImages,
|
||||
@@ -8062,6 +8125,7 @@ func (e *businessEngine) businessCommands() map[string]func([]platformValue) (an
|
||||
"ofdgoUpdateTextSelection": e.updateTextSelection,
|
||||
"ofdgoStyleText": e.styleText,
|
||||
"ofdgoFormatText": e.formatText,
|
||||
"ofdgoStyleTextFonts": e.styleTextFonts,
|
||||
"ofdgoGetRichText": e.getRichText,
|
||||
"ofdgoRichTextFonts": e.richTextFonts,
|
||||
"ofdgoSaveRichText": e.saveRichText,
|
||||
|
||||
@@ -1049,7 +1049,7 @@ func (h *Host) readFonts() {
|
||||
continue
|
||||
}
|
||||
for _, face := range faces {
|
||||
h.fonts = append(h.fonts, map[string]any{"index": face.Index, "postscriptName": face.PostScriptName, "fullName": face.FullName, "family": face.Family, "style": face.Style, "names": face.Names, "file": file})
|
||||
h.fonts = append(h.fonts, map[string]any{"index": face.Index, "postscriptName": face.PostScriptName, "fullName": face.FullName, "family": face.Family, "style": face.Style, "names": face.Names, "menuFamily": face.MenuFamily, "menuStyle": face.MenuStyle, "familyKey": face.FamilyKey, "bold": face.Bold, "italic": face.Italic, "file": file})
|
||||
for _, alias := range append([]string{face.FullName, face.Family, face.PostScriptName, strings.TrimSpace(face.Family + " " + face.Style)}, face.Names...) {
|
||||
if alias != "" && h.fontFiles[alias+".ttf"] == "" {
|
||||
h.fontFiles[alias+".ttf"] = name + "\x00" + strconv.Itoa(face.Index)
|
||||
|
||||
Reference in new issue
Block a user