pptxtojson 1.0.2 → 1.1.0

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.
package/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="utf-8">
5
5
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <meta name="description" content="基于JavaScript的 .pptx 文件解析工具丨A javascript tool for parsing .pptx file" />
8
- <meta name="keywords" content="ppt,powerpoint,office powerpoint,json,javascript,PPT解析,PPT转JSON" />
7
+ <meta name="description" content="Office PowerPoint(.pptx) file to JSON | PPTX 文件转为可读的 JSON 数据" />
8
+ <meta name="keywords" content="pptx2json,pptxtojson,ppt,powerpoint,json,javascript,PPT解析,PPT转JSON" />
9
9
  <link rel="icon" href="favicon.ico">
10
10
  <title>pptxtojson - PPTX转JSON</title>
11
11
 
@@ -80,6 +80,13 @@
80
80
  .upload-input {
81
81
  display: none;
82
82
  }
83
+ .link {
84
+ display: flex;
85
+ }
86
+ .link a {
87
+ padding: 5px 10px;
88
+ color: #d14424;
89
+ }
83
90
  </style>
84
91
  </head>
85
92
 
@@ -90,7 +97,10 @@
90
97
  <input class="upload-input" type="file" accept="application/vnd.openxmlformats-officedocument.presentationml.presentation"/>
91
98
  </div>
92
99
 
93
- <a href="https://github.com/pipipi-pikachu/pptx2json">Github</a>
100
+ <div class="link">
101
+ <a target="_blank" href="https://github.com/pipipi-pikachu/pptx2json">Github仓库</a>
102
+ <a target="_blank" href="https://pipipi-pikachu.github.io/PPTist/">可视化测试</a>
103
+ </div>
94
104
  </div>
95
105
  <div id="jsoneditor"></div>
96
106
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptxtojson",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "A javascript tool for parsing .pptx file",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",
@@ -24,7 +24,7 @@
24
24
  "homepage": "https://github.com/pipipi-pikachu/pptxtojson",
25
25
  "license": "MIT",
26
26
  "publishConfig": {
27
- "registry": "https://registry.npmjs.org"
27
+ "registry": "https://registry.npmjs.com"
28
28
  },
29
29
  "dependencies": {
30
30
  "jszip": "^3.10.1",
package/src/fill.js CHANGED
@@ -452,9 +452,9 @@ export function getShapeFill(node, isSvgMode, warpObj) {
452
452
  }
453
453
 
454
454
  export function getSolidFill(solidFill, clrMap, phClr, warpObj) {
455
- if (!solidFill) return solidFill
455
+ if (!solidFill) return ''
456
456
 
457
- let color = '#ffffff'
457
+ let color = ''
458
458
  let clrNode
459
459
 
460
460
  if (solidFill['a:srgbClr']) {
@@ -464,7 +464,7 @@ export function getSolidFill(solidFill, clrMap, phClr, warpObj) {
464
464
  else if (solidFill['a:schemeClr']) {
465
465
  clrNode = solidFill['a:schemeClr']
466
466
  const schemeClr = 'a:' + getTextByPathList(clrNode, ['attrs', 'val'])
467
- color = getSchemeColorFromTheme(schemeClr, warpObj, clrMap, phClr) || '#ffffff'
467
+ color = getSchemeColorFromTheme(schemeClr, warpObj, clrMap, phClr) || ''
468
468
  }
469
469
  else if (solidFill['a:scrgbClr']) {
470
470
  clrNode = solidFill['a:scrgbClr']
package/src/fontStyle.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { getTextByPathList } from './utils'
2
2
  import { getShadow } from './shadow'
3
+ import { getFillType, getSolidFill } from './fill'
3
4
 
4
5
  export function getFontType(node, type, warpObj) {
5
6
  let typeface = getTextByPathList(node, ['a:rPr', 'a:latin', 'attrs', 'typeface'])
@@ -21,9 +22,30 @@ export function getFontType(node, type, warpObj) {
21
22
  return typeface || ''
22
23
  }
23
24
 
24
- export function getFontColor(node) {
25
- const color = getTextByPathList(node, ['a:rPr', 'a:solidFill', 'a:srgbClr', 'attrs', 'val'])
26
- return color ? `#${color}` : ''
25
+ export function getFontColor(node, pNode, lstStyle, pFontStyle, lvl, warpObj) {
26
+ const rPrNode = getTextByPathList(node, ['a:rPr'])
27
+ let filTyp, color
28
+ if (rPrNode) {
29
+ filTyp = getFillType(rPrNode)
30
+ if (filTyp === 'SOLID_FILL') {
31
+ const solidFillNode = rPrNode['a:solidFill']
32
+ color = getSolidFill(solidFillNode, undefined, undefined, warpObj)
33
+ }
34
+ }
35
+ if (!color && getTextByPathList(lstStyle, ['a:lvl' + lvl + 'pPr', 'a:defRPr'])) {
36
+ const lstStyledefRPr = getTextByPathList(lstStyle, ['a:lvl' + lvl + 'pPr', 'a:defRPr'])
37
+ filTyp = getFillType(lstStyledefRPr)
38
+ if (filTyp === 'SOLID_FILL') {
39
+ const solidFillNode = lstStyledefRPr['a:solidFill']
40
+ color = getSolidFill(solidFillNode, undefined, undefined, warpObj)
41
+ }
42
+ }
43
+ if (!color) {
44
+ const sPstyle = getTextByPathList(pNode, ['p:style', 'a:fontRef'])
45
+ if (sPstyle) color = getSolidFill(sPstyle, undefined, undefined, warpObj)
46
+ if (!color && pFontStyle) color = getSolidFill(pFontStyle, undefined, undefined, warpObj)
47
+ }
48
+ return color || ''
27
49
  }
28
50
 
29
51
  export function getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles) {
package/src/math.js ADDED
@@ -0,0 +1,184 @@
1
+ import { getTextByPathList } from './utils'
2
+
3
+ export function findOMath(obj) {
4
+ let results = []
5
+ if (typeof obj !== 'object') return results
6
+ if (obj['m:oMath']) results = results.concat(obj['m:oMath'])
7
+
8
+ Object.values(obj).forEach(value => {
9
+ if (Array.isArray(value) || typeof value === 'object') {
10
+ results = results.concat(findOMath(value))
11
+ }
12
+ })
13
+ return results
14
+ }
15
+
16
+ export function parseFraction(fraction) {
17
+ const numerator = parseOMath(fraction['m:num'])
18
+ const denominator = parseOMath(fraction['m:den'])
19
+ return `\\frac{${numerator}}{${denominator}}`
20
+ }
21
+ export function parseSuperscript(superscript) {
22
+ const base = parseOMath(superscript['m:e'])
23
+ const sup = parseOMath(superscript['m:sup'])
24
+ return `${base}^{${sup}}`
25
+ }
26
+ export function parseSubscript(subscript) {
27
+ const base = parseOMath(subscript['m:e'])
28
+ const sub = parseOMath(subscript['m:sub'])
29
+ return `${base}_{${sub}}`
30
+ }
31
+ export function parseRadical(radical) {
32
+ const degree = parseOMath(radical['m:deg'])
33
+ const expression = parseOMath(radical['m:e'])
34
+ return degree ? `\\sqrt[${degree}]{${expression}}` : `\\sqrt{${expression}}`
35
+ }
36
+ export function parseMatrix(matrix) {
37
+ const rows = matrix['m:mr']
38
+ const matrixRows = rows.map((row) => {
39
+ return row['m:e'].map((element) => parseOMath(element)).join(' & ')
40
+ })
41
+ return `\\begin{matrix} ${matrixRows.join(' \\\\ ')} \\end{matrix}`
42
+ }
43
+ export function parseNary(nary) {
44
+ const op = getTextByPathList(nary, ['m:naryPr', 'm:chr', 'attrs', 'm:val']) || '∫'
45
+ const sub = parseOMath(nary['m:sub'])
46
+ const sup = parseOMath(nary['m:sup'])
47
+ const e = parseOMath(nary['m:e'])
48
+ return `${op}_{${sub}}^{${sup}}{${e}}`
49
+ }
50
+ export function parseLimit(limit, type) {
51
+ const base = parseOMath(limit['m:e'])
52
+ const lim = parseOMath(limit['m:lim'])
53
+ return type === 'low' ? `${base}_{${lim}}` : `${base}^{${lim}}`
54
+ }
55
+ export function parseDelimiter(delimiter) {
56
+ let left = getTextByPathList(delimiter, ['m:dPr', 'm:begChr', 'attrs', 'm:val'])
57
+ let right = getTextByPathList(delimiter, ['m:dPr', 'm:endChr', 'attrs', 'm:val'])
58
+ if (!left && !right) {
59
+ left = '('
60
+ right = ')'
61
+ }
62
+ if (left && right) {
63
+ left = `\\left${left}`
64
+ right = `\\right${right}`
65
+ }
66
+ const e = parseOMath(delimiter['m:e'])
67
+ return `${left}${e}${right}`
68
+ }
69
+ export function parseFunction(func) {
70
+ const name = parseOMath(func['m:fName'])
71
+ const arg = parseOMath(func['m:e'])
72
+ return `\\${name}{${arg}}`
73
+ }
74
+ export function parseGroupChr(groupChr) {
75
+ const chr = getTextByPathList(groupChr, ['m:groupChrPr', 'm:chr', 'attrs', 'm:val'])
76
+ const e = parseOMath(groupChr['m:e'])
77
+ return `${chr}${e}${chr}`
78
+ }
79
+ export function parseEqArr(eqArr) {
80
+ const equations = eqArr['m:e'].map((eq) => parseOMath(eq)).join(' \\\\ ')
81
+ return `\\begin{cases} ${equations} \\end{cases}`
82
+ }
83
+ export function parseBar(bar) {
84
+ const e = parseOMath(bar['m:e'])
85
+ const pos = getTextByPathList(bar, ['m:barPr', 'm:pos', 'attrs', 'm:val'])
86
+ return pos === 'top' ? `\\overline{${e}}` : `\\underline{${e}}`
87
+ }
88
+ export function parseAccent(accent) {
89
+ const chr = getTextByPathList(accent, ['m:accPr', 'm:chr', 'attrs', 'm:val']) || '^'
90
+ const e = parseOMath(accent['m:e'])
91
+ switch (chr) {
92
+ case '\u0301':
93
+ return `\\acute{${e}}`
94
+ case '\u0300':
95
+ return `\\grave{${e}}`
96
+ case '\u0302':
97
+ return `\\hat{${e}}`
98
+ case '\u0303':
99
+ return `\\tilde{${e}}`
100
+ case '\u0304':
101
+ return `\\bar{${e}}`
102
+ case '\u0306':
103
+ return `\\breve{${e}}`
104
+ case '\u0307':
105
+ return `\\dot{${e}}`
106
+ case '\u0308':
107
+ return `\\ddot{${e}}`
108
+ case '\u030A':
109
+ return `\\mathring{${e}}`
110
+ case '\u030B':
111
+ return `\\H{${e}}`
112
+ case '\u030C':
113
+ return `\\check{${e}}`
114
+ case '\u0327':
115
+ return `\\c{${e}}`
116
+ default:
117
+ return `\\${chr}{${e}}`
118
+ }
119
+ }
120
+ export function parseBox(box) {
121
+ const e = parseOMath(box['m:e'])
122
+ return `\\boxed{${e}}`
123
+ }
124
+
125
+
126
+ export function parseOMath(oMath) {
127
+ if (!oMath) return ''
128
+
129
+ if (Array.isArray(oMath)) {
130
+ return oMath.map(item => parseOMath(item)).join('')
131
+ }
132
+
133
+ const oMathList = []
134
+ const keys = Object.keys(oMath)
135
+ for (const key of keys) {
136
+ if (Array.isArray(oMath[key])) {
137
+ oMathList.push(...oMath[key].map(item => ({ key, value: item })))
138
+ }
139
+ else oMathList.push({ key, value: oMath[key] })
140
+ }
141
+
142
+ oMathList.sort((a, b) => {
143
+ let oA = 0
144
+ if (a.key === 'm:r' && a.value && a.value['a:rPr']) oA = a.value['a:rPr']['attrs']['order']
145
+ else if (a.value[`${a.key}Pr`] && a.value[`${a.key}Pr`]['m:ctrlPr'] && a.value[`${a.key}Pr`]['m:ctrlPr']['a:rPr']) {
146
+ oA = a.value[`${a.key}Pr`] && a.value[`${a.key}Pr`]['m:ctrlPr'] && a.value[`${a.key}Pr`]['m:ctrlPr']['a:rPr'] && a.value[`${a.key}Pr`]['m:ctrlPr']['a:rPr']['attrs']['order']
147
+ }
148
+ let oB = 0
149
+ if (b.key === 'm:r' && b.value && b.value['a:rPr']) oB = b.value['a:rPr']['attrs']['order']
150
+ else if (b.value[`${b.key}Pr`] && b.value[`${b.key}Pr`]['m:ctrlPr'] && b.value[`${b.key}Pr`]['m:ctrlPr']['a:rPr']) {
151
+ oB = b.value[`${b.key}Pr`] && b.value[`${b.key}Pr`]['m:ctrlPr'] && b.value[`${b.key}Pr`]['m:ctrlPr']['a:rPr'] && b.value[`${b.key}Pr`]['m:ctrlPr']['a:rPr']['attrs']['order']
152
+ }
153
+ return oA - oB
154
+ })
155
+
156
+ return oMathList.map(({ key, value }) => {
157
+ if (key === 'm:f') return parseFraction(value)
158
+ if (key === 'm:sSup') return parseSuperscript(value)
159
+ if (key === 'm:sSub') return parseSubscript(value)
160
+ if (key === 'm:rad') return parseRadical(value)
161
+ if (key === 'm:nary') return parseNary(value)
162
+ if (key === 'm:limLow') return parseLimit(value, 'low')
163
+ if (key === 'm:limUpp') return parseLimit(value, 'upp')
164
+ if (key === 'm:d') return parseDelimiter(value)
165
+ if (key === 'm:func') return parseFunction(value)
166
+ if (key === 'm:groupChr') return parseGroupChr(value)
167
+ if (key === 'm:eqArr') return parseEqArr(value)
168
+ if (key === 'm:bar') return parseBar(value)
169
+ if (key === 'm:acc') return parseAccent(value)
170
+ if (key === 'm:borderBox') return parseBox(value)
171
+ if (key === 'm:m') return parseMatrix(value)
172
+ if (key === 'm:r') return parseOMath(value)
173
+ if (key === 'm:t') return value
174
+ return ''
175
+ }).join('')
176
+ }
177
+
178
+ export function latexFormart(latex) {
179
+ return latex.replaceAll(/&lt;/g, '<')
180
+ .replaceAll(/&gt;/g, '>')
181
+ .replaceAll(/&amp;/g, '&')
182
+ .replaceAll(/&apos;/g, "'")
183
+ .replaceAll(/&quot;/g, '"')
184
+ }
package/src/pptxtojson.js CHANGED
@@ -11,6 +11,7 @@ import { extractFileExtension, base64ArrayBuffer, getTextByPathList, angleToDegr
11
11
  import { getShadow } from './shadow'
12
12
  import { getTableBorders, getTableCellParams, getTableRowParams } from './table'
13
13
  import { RATIO_EMUs_Points } from './constants'
14
+ import { findOMath, latexFormart, parseOMath } from './math'
14
15
 
15
16
  export async function parse(file) {
16
17
  const slides = []
@@ -105,6 +106,7 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
105
106
  let relationshipArray = resContent['Relationships']['Relationship']
106
107
  let layoutFilename = ''
107
108
  let diagramFilename = ''
109
+ let notesFilename = ''
108
110
  const slideResObj = {}
109
111
 
110
112
  if (relationshipArray.constructor === Array) {
@@ -121,6 +123,8 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
121
123
  }
122
124
  break
123
125
  case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide':
126
+ notesFilename = relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
127
+ break
124
128
  case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image':
125
129
  case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart':
126
130
  case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink':
@@ -133,6 +137,9 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
133
137
  }
134
138
  }
135
139
  else layoutFilename = relationshipArray['attrs']['Target'].replace('../', 'ppt/')
140
+
141
+ const slideNotesContent = await readXmlFile(zip, notesFilename)
142
+ const note = getNote(slideNotesContent)
136
143
 
137
144
  const slideLayoutContent = await readXmlFile(zip, layoutFilename)
138
145
  const slideLayoutTables = await indexNodes(slideLayoutContent)
@@ -283,9 +290,29 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
283
290
  return {
284
291
  fill: bgColor,
285
292
  elements,
293
+ note,
286
294
  }
287
295
  }
288
296
 
297
+ function getNote(noteContent) {
298
+ let text = ''
299
+ let spNodes = getTextByPathList(noteContent, ['p:notes', 'p:cSld', 'p:spTree', 'p:sp'])
300
+ if (!spNodes) return ''
301
+
302
+ if (spNodes.constructor !== Array) spNodes = [spNodes]
303
+ for (const spNode of spNodes) {
304
+ let rNodes = getTextByPathList(spNode, ['p:txBody', 'a:p', 'a:r'])
305
+ if (!rNodes) continue
306
+
307
+ if (rNodes.constructor !== Array) rNodes = [rNodes]
308
+ for (const rNode of rNodes) {
309
+ const t = getTextByPathList(rNode, ['a:t'])
310
+ if (t) text += t
311
+ }
312
+ }
313
+ return text
314
+ }
315
+
289
316
  // async function getBackground(warpObj) {
290
317
  // const elements = []
291
318
  // const slideLayoutContent = warpObj['slideLayoutContent']
@@ -390,7 +417,12 @@ async function processNodesInSlide(nodeKey, nodeValue, warpObj, source) {
390
417
  json = await processGroupSpNode(nodeValue, warpObj, source)
391
418
  break
392
419
  case 'mc:AlternateContent':
393
- json = await processGroupSpNode(getTextByPathList(nodeValue, ['mc:Fallback']), warpObj, source)
420
+ if (getTextByPathList(nodeValue, ['mc:Fallback', 'p:grpSpPr', 'a:xfrm'])) {
421
+ json = await processGroupSpNode(getTextByPathList(nodeValue, ['mc:Fallback']), warpObj, source)
422
+ }
423
+ else if (getTextByPathList(nodeValue, ['mc:Choice'])) {
424
+ json = await processMathNode(getTextByPathList(nodeValue, ['mc:Choice']))
425
+ }
394
426
  break
395
427
  default:
396
428
  }
@@ -398,6 +430,24 @@ async function processNodesInSlide(nodeKey, nodeValue, warpObj, source) {
398
430
  return json
399
431
  }
400
432
 
433
+ function processMathNode(node) {
434
+ const xfrmNode = getTextByPathList(node, ['p:sp', 'p:spPr', 'a:xfrm'])
435
+ const { top, left } = getPosition(xfrmNode, undefined, undefined)
436
+ const { width, height } = getSize(xfrmNode, undefined, undefined)
437
+
438
+ const oMath = findOMath(node)[0]
439
+ const latex = latexFormart(parseOMath(oMath))
440
+
441
+ return {
442
+ type: 'math',
443
+ top,
444
+ left,
445
+ width,
446
+ height,
447
+ latex,
448
+ }
449
+ }
450
+
401
451
  async function processGroupSpNode(node, warpObj, source) {
402
452
  const xfrmNode = getTextByPathList(node, ['p:grpSpPr', 'a:xfrm'])
403
453
  if (!xfrmNode) return null
@@ -410,7 +460,10 @@ async function processGroupSpNode(node, warpObj, source) {
410
460
  const cy = parseInt(xfrmNode['a:ext']['attrs']['cy']) * RATIO_EMUs_Points
411
461
  const chcx = parseInt(xfrmNode['a:chExt']['attrs']['cx']) * RATIO_EMUs_Points
412
462
  const chcy = parseInt(xfrmNode['a:chExt']['attrs']['cy']) * RATIO_EMUs_Points
413
- // children coordinate
463
+
464
+ let rotate = getTextByPathList(xfrmNode, ['attrs', 'rot']) || 0
465
+ if (rotate) rotate = angleToDegrees(rotate)
466
+
414
467
  const ws = cx / chcx
415
468
  const hs = cy / chcy
416
469
 
@@ -434,6 +487,7 @@ async function processGroupSpNode(node, warpObj, source) {
434
487
  left: x,
435
488
  width: cx,
436
489
  height: cy,
490
+ rotate,
437
491
  elements: elements.map(element => ({
438
492
  ...element,
439
493
  left: (element.left - chx) * ws,
package/src/table.js CHANGED
@@ -3,7 +3,7 @@ import { getTextByPathList } from './utils'
3
3
  import { getBorder } from './border'
4
4
 
5
5
  export function getTableBorders(node, warpObj) {
6
- let borderStyles = {}
6
+ const borderStyles = {}
7
7
  if (node['a:bottom']) {
8
8
  const obj = {
9
9
  'p:spPr': {
package/src/text.js CHANGED
@@ -19,6 +19,8 @@ export function genTextBody(textBodyNode, spNode, slideLayoutSpNode, type, warpO
19
19
 
20
20
  let text = ''
21
21
 
22
+ const pFontStyle = getTextByPathList(spNode, ['p:style', 'a:fontRef'])
23
+
22
24
  const pNode = textBodyNode['a:p']
23
25
  const pNodes = pNode.constructor === Array ? pNode : [pNode]
24
26
 
@@ -71,10 +73,10 @@ export function genTextBody(textBodyNode, spNode, slideLayoutSpNode, type, warpO
71
73
  text += `<p style="text-align: ${align};">`
72
74
  }
73
75
 
74
- if (!rNode) text += genSpanElement(pNode, slideLayoutSpNode, type, warpObj)
76
+ if (!rNode) text += genSpanElement(pNode, spNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
75
77
  else {
76
78
  for (const rNodeItem of rNode) {
77
- text += genSpanElement(rNodeItem, slideLayoutSpNode, type, warpObj)
79
+ text += genSpanElement(rNodeItem, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
78
80
  }
79
81
  }
80
82
 
@@ -94,15 +96,21 @@ export function getListType(node) {
94
96
  return ''
95
97
  }
96
98
 
97
- export function genSpanElement(node, slideLayoutSpNode, type, warpObj) {
99
+ export function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj) {
100
+ const lstStyle = textBodyNode['a:lstStyle']
98
101
  const slideMasterTextStyles = warpObj['slideMasterTextStyles']
99
102
 
103
+ let lvl = 1
104
+ const pPrNode = pNode['a:pPr']
105
+ const lvlNode = getTextByPathList(pPrNode, ['attrs', 'lvl'])
106
+ if (lvlNode !== undefined) lvl = parseInt(lvlNode) + 1
107
+
100
108
  let text = node['a:t']
101
109
  if (typeof text !== 'string') text = getTextByPathList(node, ['a:fld', 'a:t'])
102
110
  if (typeof text !== 'string') text = '&nbsp;'
103
111
 
104
112
  let styleText = ''
105
- const fontColor = getFontColor(node)
113
+ const fontColor = getFontColor(node, pNode, lstStyle, pFontStyle, lvl, warpObj)
106
114
  const fontSize = getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles)
107
115
  const fontType = getFontType(node, type, warpObj)
108
116
  const fontBold = getFontBold(node)