@courtifyai/docx-render 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,258 +0,0 @@
1
- /**
2
- * 字体表解析器
3
- * 解析 word/fontTable.xml,提取字体声明、嵌入字体引用和字体替换映射
4
- */
5
-
6
- import { xmlParser, parseXmlString } from '../parser/xml-parser'
7
- import {
8
- IFontTable,
9
- IFontDeclaration,
10
- IEmbedFontRef,
11
- IFontSignature,
12
- TEmbedFontType,
13
- } from '../types'
14
-
15
- /**
16
- * 嵌入字体元素名到类型的映射
17
- */
18
- const EMBED_FONT_TYPE_MAP: Record<string, TEmbedFontType> = {
19
- embedRegular: 'regular',
20
- embedBold: 'bold',
21
- embedItalic: 'italic',
22
- embedBoldItalic: 'boldItalic',
23
- }
24
-
25
- /**
26
- * 解析字体表 XML
27
- * @param xmlContent fontTable.xml 的内容
28
- * @returns 字体表对象
29
- */
30
- export function parseFontTable(xmlContent: string): IFontTable {
31
- const doc = parseXmlString(xmlContent)
32
- const root = doc.documentElement
33
-
34
- const fonts = parseFonts(root)
35
- const fontMap = new Map(fonts.map(f => [f.name, f]))
36
- const substitutionMap = buildSubstitutionMap(fonts)
37
-
38
- return {
39
- fonts,
40
- fontMap,
41
- substitutionMap,
42
- }
43
- }
44
-
45
- /**
46
- * 解析所有字体声明
47
- */
48
- function parseFonts(root: Element): IFontDeclaration[] {
49
- return xmlParser.elements(root, 'font').map(el => parseFont(el))
50
- }
51
-
52
- /**
53
- * 解析单个字体声明
54
- */
55
- function parseFont(elem: Element): IFontDeclaration {
56
- const result: IFontDeclaration = {
57
- name: xmlParser.attr(elem, 'name') || '',
58
- embedFontRefs: [],
59
- }
60
-
61
- for (const el of xmlParser.elements(elem)) {
62
- switch (el.localName) {
63
- case 'family':
64
- result.family = xmlParser.attr(el, 'val')
65
- break
66
-
67
- case 'altName':
68
- result.altName = xmlParser.attr(el, 'val')
69
- break
70
-
71
- case 'charset':
72
- result.charset = xmlParser.attr(el, 'val')
73
- break
74
-
75
- case 'panose1':
76
- result.panose1 = xmlParser.attr(el, 'val')
77
- break
78
-
79
- case 'sig':
80
- result.sig = parseFontSignature(el)
81
- break
82
-
83
- case 'embedRegular':
84
- case 'embedBold':
85
- case 'embedItalic':
86
- case 'embedBoldItalic':
87
- const embedRef = parseEmbedFontRef(el)
88
- if (embedRef) {
89
- result.embedFontRefs.push(embedRef)
90
- }
91
- break
92
- }
93
- }
94
-
95
- return result
96
- }
97
-
98
- /**
99
- * 解析字体签名
100
- */
101
- function parseFontSignature(elem: Element): IFontSignature {
102
- return {
103
- usb0: xmlParser.attr(elem, 'usb0'),
104
- usb1: xmlParser.attr(elem, 'usb1'),
105
- usb2: xmlParser.attr(elem, 'usb2'),
106
- usb3: xmlParser.attr(elem, 'usb3'),
107
- csb0: xmlParser.attr(elem, 'csb0'),
108
- csb1: xmlParser.attr(elem, 'csb1'),
109
- }
110
- }
111
-
112
- /**
113
- * 解析嵌入字体引用
114
- */
115
- function parseEmbedFontRef(elem: Element): IEmbedFontRef | null {
116
- const id = xmlParser.attr(elem, 'id')
117
- if (!id) return null
118
-
119
- const type = EMBED_FONT_TYPE_MAP[elem.localName]
120
- if (!type) return null
121
-
122
- return {
123
- id,
124
- key: xmlParser.attr(elem, 'fontKey'),
125
- subsetted: xmlParser.boolAttr(elem, 'subsetted'),
126
- type,
127
- }
128
- }
129
-
130
- /**
131
- * 构建字体替换映射
132
- * 从字体声明中提取 altName,建立原字体名到替代字体名的映射
133
- */
134
- function buildSubstitutionMap(fonts: IFontDeclaration[]): Map<string, string> {
135
- const map = new Map<string, string>()
136
-
137
- for (const font of fonts) {
138
- if (font.altName) {
139
- map.set(font.name, font.altName)
140
- }
141
- }
142
-
143
- return map
144
- }
145
-
146
- /**
147
- * 获取字体的替代字体名
148
- * @param fontTable 字体表
149
- * @param fontName 原字体名
150
- * @returns 替代字体名,如果没有替代则返回原字体名
151
- */
152
- export function getSubstituteFontName(fontTable: IFontTable, fontName: string): string {
153
- return fontTable.substitutionMap.get(fontName) || fontName
154
- }
155
-
156
- /**
157
- * 获取字体声明
158
- * @param fontTable 字体表
159
- * @param fontName 字体名
160
- * @returns 字体声明,如果不存在则返回 undefined
161
- */
162
- export function getFontDeclaration(fontTable: IFontTable, fontName: string): IFontDeclaration | undefined {
163
- return fontTable.fontMap.get(fontName)
164
- }
165
-
166
- /**
167
- * 检查字体是否有嵌入字体
168
- * @param fontTable 字体表
169
- * @param fontName 字体名
170
- * @returns 是否有嵌入字体
171
- */
172
- export function hasEmbeddedFont(fontTable: IFontTable, fontName: string): boolean {
173
- const font = fontTable.fontMap.get(fontName)
174
- return font ? font.embedFontRefs.length > 0 : false
175
- }
176
-
177
- /**
178
- * 获取字体的嵌入字体引用
179
- * @param fontTable 字体表
180
- * @param fontName 字体名
181
- * @param type 字体类型(可选,不指定则返回所有类型)
182
- * @returns 嵌入字体引用数组
183
- */
184
- export function getEmbedFontRefs(
185
- fontTable: IFontTable,
186
- fontName: string,
187
- type?: TEmbedFontType
188
- ): IEmbedFontRef[] {
189
- const font = fontTable.fontMap.get(fontName)
190
- if (!font) return []
191
-
192
- if (type) {
193
- return font.embedFontRefs.filter(ref => ref.type === type)
194
- }
195
-
196
- return font.embedFontRefs
197
- }
198
-
199
- /**
200
- * 生成 CSS font-family 字符串
201
- * 根据字体声明生成包含替代字体的 font-family
202
- * @param fontTable 字体表
203
- * @param fontName 字体名
204
- * @returns CSS font-family 字符串
205
- */
206
- export function buildFontFamily(fontTable: IFontTable, fontName: string): string {
207
- const fonts: string[] = []
208
- const font = fontTable.fontMap.get(fontName)
209
-
210
- // 添加原字体名
211
- fonts.push(quoteFontName(fontName))
212
-
213
- // 添加替代字体
214
- if (font?.altName) {
215
- fonts.push(quoteFontName(font.altName))
216
- }
217
-
218
- // 根据字体家族添加通用字体
219
- if (font?.family) {
220
- const genericFont = getGenericFontFamily(font.family)
221
- if (genericFont) {
222
- fonts.push(genericFont)
223
- }
224
- }
225
-
226
- return fonts.join(', ')
227
- }
228
-
229
- /**
230
- * 为字体名添加引号(如果需要)
231
- */
232
- function quoteFontName(name: string): string {
233
- // 如果字体名包含空格或特殊字符,需要加引号
234
- if (/[\s,'"()]/.test(name)) {
235
- return `"${name.replace(/"/g, '\\"')}"`
236
- }
237
- return name
238
- }
239
-
240
- /**
241
- * 根据 OOXML 字体家族获取 CSS 通用字体家族
242
- */
243
- function getGenericFontFamily(family: string): string | null {
244
- switch (family.toLowerCase()) {
245
- case 'roman':
246
- return 'serif'
247
- case 'swiss':
248
- return 'sans-serif'
249
- case 'modern':
250
- return 'monospace'
251
- case 'script':
252
- return 'cursive'
253
- case 'decorative':
254
- return 'fantasy'
255
- default:
256
- return null
257
- }
258
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * 字体表模块
3
- * 提供字体表解析、嵌入字体加载和字体替换映射功能
4
- */
5
-
6
- // 导出解析器
7
- export {
8
- parseFontTable,
9
- getSubstituteFontName,
10
- getFontDeclaration,
11
- hasEmbeddedFont,
12
- getEmbedFontRefs,
13
- buildFontFamily,
14
- } from './font-parser'
15
-
16
- // 导出加载器
17
- export {
18
- loadEmbeddedFonts,
19
- cleanupFontStyles,
20
- parseFontRelationships,
21
- type IFontLoaderOptions,
22
- } from './font-loader'
package/src/index.ts DELETED
@@ -1,137 +0,0 @@
1
- /**
2
- * DOCX Render
3
- * 自研 DOCX 渲染库,参考 docx-preview 架构
4
- * 支持文档和评论一体化渲染,评论连接线
5
- */
6
-
7
- import { DocumentParser } from './parser'
8
- import { DocumentRenderer } from './renderer'
9
- import { IRendererOptions, IDocxDocument, ICommentElement } from './types'
10
-
11
- // 样式
12
- import './styles/index.css'
13
-
14
- // 导出类型
15
- export type {
16
- IDocxDocument,
17
- ICommentElement,
18
- ICommentExtended,
19
- IRendererOptions,
20
- IOpenXmlElement,
21
- IParagraphElement,
22
- IRunElement,
23
- IRunProperties,
24
- ITextElement,
25
- ITableElement,
26
- ITheme,
27
- IColorScheme,
28
- IFontScheme,
29
- IThemeColors,
30
- IThemeColorRef,
31
- IFootnoteElement,
32
- IEndnoteElement,
33
- IFootnoteReference,
34
- IEndnoteReference,
35
- // 书签类型
36
- IBookmarkStartElement,
37
- IBookmarkEndElement,
38
- // Symbol 元素
39
- ISymbolElement,
40
- // 字体表类型
41
- IFontTable,
42
- IFontDeclaration,
43
- IEmbedFontRef,
44
- IFontSignature,
45
- ILoadedEmbedFont,
46
- TEmbedFontType,
47
- // 下划线样式类型
48
- TUnderlineStyle,
49
- } from './types'
50
-
51
- // 导出常量
52
- export { DomType, DOCX_PARTS, XML_NS } from './types'
53
-
54
- // 导出解析器
55
- export { DocumentParser } from './parser'
56
-
57
- // 导出渲染器
58
- export { DocumentRenderer } from './renderer'
59
-
60
- // 导出主题工具
61
- export { parseTheme, resolveThemeColor, applyTintShade, resolveThemeFont } from './theme'
62
-
63
- // 导出字体表工具
64
- export {
65
- parseFontTable,
66
- getSubstituteFontName,
67
- getFontDeclaration,
68
- hasEmbeddedFont,
69
- getEmbedFontRefs,
70
- buildFontFamily,
71
- loadEmbeddedFonts,
72
- cleanupFontStyles,
73
- } from './font-table'
74
-
75
- // 导出评论工具
76
- export { parseCommentsExtended, buildCommentTree } from './comments'
77
-
78
- /**
79
- * DOCX 渲染器类
80
- * 整合解析器和渲染器,提供完整的渲染能力
81
- */
82
- export class DocxRender {
83
- private parser: DocumentParser
84
- private renderer: DocumentRenderer
85
- private document: IDocxDocument | null = null
86
-
87
- constructor(options: IRendererOptions) {
88
- this.parser = new DocumentParser()
89
- this.renderer = new DocumentRenderer(options)
90
- }
91
-
92
- /**
93
- * 渲染 DOCX 文件
94
- */
95
- async render(file: File | ArrayBuffer | Blob): Promise<void> {
96
- this.document = await this.parser.parse(file)
97
- this.renderer.render(this.document)
98
- }
99
-
100
- /**
101
- * 获取文档对象
102
- */
103
- getDocument(): IDocxDocument | null {
104
- return this.document
105
- }
106
-
107
- /**
108
- * 获取所有评论
109
- */
110
- getComments(): ICommentElement[] {
111
- return this.document?.comments || []
112
- }
113
-
114
- /**
115
- * 获取解析器(用于保存修改)
116
- */
117
- getParser(): DocumentParser {
118
- return this.parser
119
- }
120
- }
121
-
122
- /**
123
- * 便捷方法:快速渲染 DOCX 文件
124
- */
125
- export async function renderDocx(
126
- file: File | ArrayBuffer | Blob,
127
- container: HTMLElement | string,
128
- options?: Partial<IRendererOptions>
129
- ): Promise<DocxRender> {
130
- const render = new DocxRender({
131
- container,
132
- ...options,
133
- })
134
-
135
- await render.render(file)
136
- return render
137
- }