pptxtojson 1.6.1 → 1.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptxtojson",
3
- "version": "1.6.1",
3
+ "version": "1.8.0",
4
4
  "description": "A javascript tool for parsing .pptx file",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",
package/src/fill.js CHANGED
@@ -85,6 +85,79 @@ export function getPicFillOpacity(node) {
85
85
  return opacity
86
86
  }
87
87
 
88
+ export function getPicFilters(node) {
89
+ if (!node) return null
90
+
91
+ const aBlipNode = node['a:blip']
92
+ if (!aBlipNode) return null
93
+
94
+ const filters = {}
95
+
96
+ // 从a:extLst中获取滤镜效果(Microsoft Office 2010+扩展)
97
+ const extLstNode = aBlipNode['a:extLst']
98
+ if (extLstNode && extLstNode['a:ext']) {
99
+ const extNodes = Array.isArray(extLstNode['a:ext']) ? extLstNode['a:ext'] : [extLstNode['a:ext']]
100
+
101
+ for (const extNode of extNodes) {
102
+ if (!extNode['a14:imgProps'] || !extNode['a14:imgProps']['a14:imgLayer']) continue
103
+
104
+ const imgLayerNode = extNode['a14:imgProps']['a14:imgLayer']
105
+ const imgEffects = imgLayerNode['a14:imgEffect']
106
+
107
+ if (!imgEffects) continue
108
+
109
+ const effectArray = Array.isArray(imgEffects) ? imgEffects : [imgEffects]
110
+
111
+ for (const effect of effectArray) {
112
+ // 饱和度
113
+ if (effect['a14:saturation']) {
114
+ const satAttr = getTextByPathList(effect, ['a14:saturation', 'attrs', 'sat'])
115
+ if (satAttr) {
116
+ filters.saturation = parseInt(satAttr) / 100000
117
+ }
118
+ }
119
+
120
+ // 亮度、对比度
121
+ if (effect['a14:brightnessContrast']) {
122
+ const brightAttr = getTextByPathList(effect, ['a14:brightnessContrast', 'attrs', 'bright'])
123
+ const contrastAttr = getTextByPathList(effect, ['a14:brightnessContrast', 'attrs', 'contrast'])
124
+
125
+ if (brightAttr) {
126
+ filters.brightness = parseInt(brightAttr) / 100000
127
+ }
128
+ if (contrastAttr) {
129
+ filters.contrast = parseInt(contrastAttr) / 100000
130
+ }
131
+ }
132
+
133
+ // 锐化/柔化
134
+ if (effect['a14:sharpenSoften']) {
135
+ const amountAttr = getTextByPathList(effect, ['a14:sharpenSoften', 'attrs', 'amount'])
136
+ if (amountAttr) {
137
+ const amount = parseInt(amountAttr) / 100000
138
+ if (amount > 0) {
139
+ filters.sharpen = amount
140
+ }
141
+ else {
142
+ filters.soften = Math.abs(amount)
143
+ }
144
+ }
145
+ }
146
+
147
+ // 色温
148
+ if (effect['a14:colorTemperature']) {
149
+ const tempAttr = getTextByPathList(effect, ['a14:colorTemperature', 'attrs', 'colorTemp'])
150
+ if (tempAttr) {
151
+ filters.colorTemperature = parseInt(tempAttr)
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ return Object.keys(filters).length > 0 ? filters : null
159
+ }
160
+
88
161
  export async function getBgPicFill(bgPr, sorce, warpObj) {
89
162
  const picBase64 = await getPicFill(sorce, bgPr['a:blipFill'], warpObj)
90
163
  const aBlipNode = bgPr['a:blipFill']['a:blip']
@@ -107,7 +180,7 @@ export function getGradientFill(node, warpObj) {
107
180
  for (let i = 0; i < gsLst.length; i++) {
108
181
  const lo_color = getSolidFill(gsLst[i], undefined, undefined, warpObj)
109
182
  const pos = getTextByPathList(gsLst[i], ['attrs', 'pos'])
110
-
183
+
111
184
  colors[i] = {
112
185
  pos: pos ? (pos / 1000 + '%') : '',
113
186
  color: lo_color,
@@ -119,7 +192,7 @@ export function getGradientFill(node, warpObj) {
119
192
  if (lin) rot = angleToDegrees(lin['attrs']['ang'])
120
193
  else {
121
194
  const path = node['a:path']
122
- if (path && path['attrs'] && path['attrs']['path']) pathType = path['attrs']['path']
195
+ if (path && path['attrs'] && path['attrs']['path']) pathType = path['attrs']['path']
123
196
  }
124
197
  return {
125
198
  rot,
@@ -128,6 +201,35 @@ export function getGradientFill(node, warpObj) {
128
201
  }
129
202
  }
130
203
 
204
+ export function getPatternFill(node, warpObj) {
205
+ if (!node) return null
206
+
207
+ const pattFill = node['a:pattFill']
208
+ if (!pattFill) return null
209
+
210
+ const type = getTextByPathList(pattFill, ['attrs', 'prst'])
211
+
212
+ const fgColorNode = pattFill['a:fgClr']
213
+ const bgColorNode = pattFill['a:bgClr']
214
+
215
+ let foregroundColor = '#000000'
216
+ let backgroundColor = '#FFFFFF'
217
+
218
+ if (fgColorNode) {
219
+ foregroundColor = getSolidFill(fgColorNode, undefined, undefined, warpObj)
220
+ }
221
+
222
+ if (bgColorNode) {
223
+ backgroundColor = getSolidFill(bgColorNode, undefined, undefined, warpObj)
224
+ }
225
+
226
+ return {
227
+ type,
228
+ foregroundColor,
229
+ backgroundColor,
230
+ }
231
+ }
232
+
131
233
  export function getBgGradientFill(bgPr, phClr, slideMasterContent, warpObj) {
132
234
  if (bgPr) {
133
235
  const grdFill = bgPr['a:gradFill']
@@ -204,6 +306,13 @@ export async function getSlideBackgroundFill(warpObj) {
204
306
  background = await getBgPicFill(bgPr, 'slideBg', warpObj)
205
307
  backgroundType = 'image'
206
308
  }
309
+ else if (bgFillTyp === 'PATTERN_FILL') {
310
+ const patternFill = getPatternFill(bgPr, warpObj)
311
+ if (patternFill) {
312
+ background = patternFill
313
+ backgroundType = 'pattern'
314
+ }
315
+ }
207
316
  }
208
317
  else if (bgRef) {
209
318
  let clrMapOvr
@@ -301,6 +410,13 @@ export async function getSlideBackgroundFill(warpObj) {
301
410
  background = await getBgPicFill(bgPr, 'slideLayoutBg', warpObj)
302
411
  backgroundType = 'image'
303
412
  }
413
+ else if (bgFillTyp === 'PATTERN_FILL') {
414
+ const patternFill = getPatternFill(bgPr, warpObj)
415
+ if (patternFill) {
416
+ background = patternFill
417
+ backgroundType = 'pattern'
418
+ }
419
+ }
304
420
  }
305
421
  else if (bgRef) {
306
422
  const phClr = getSolidFill(bgRef, clrMapOvr, undefined, warpObj)
@@ -347,7 +463,7 @@ export async function getSlideBackgroundFill(warpObj) {
347
463
  const sldFill = bgFillLstIdx['a:solidFill']
348
464
  const sldBgClr = getSolidFill(sldFill, clrMapOvr, undefined, warpObj)
349
465
  background = sldBgClr
350
- }
466
+ }
351
467
  else if (bgFillTyp === 'GRADIENT_FILL') {
352
468
  const gradientFill = getBgGradientFill(bgFillLstIdx, phClr, slideMasterContent, warpObj)
353
469
  if (typeof gradientFill === 'string') {
@@ -362,6 +478,13 @@ export async function getSlideBackgroundFill(warpObj) {
362
478
  background = await getBgPicFill(bgFillLstIdx, 'themeBg', warpObj)
363
479
  backgroundType = 'image'
364
480
  }
481
+ else if (bgFillTyp === 'PATTERN_FILL') {
482
+ const patternFill = getPatternFill(bgFillLstIdx, warpObj)
483
+ if (patternFill) {
484
+ background = patternFill
485
+ backgroundType = 'pattern'
486
+ }
487
+ }
365
488
  }
366
489
  }
367
490
  else {
@@ -390,6 +513,13 @@ export async function getSlideBackgroundFill(warpObj) {
390
513
  background = await getBgPicFill(bgPr, 'slideMasterBg', warpObj)
391
514
  backgroundType = 'image'
392
515
  }
516
+ else if (bgFillTyp === 'PATTERN_FILL') {
517
+ const patternFill = getPatternFill(bgPr, warpObj)
518
+ if (patternFill) {
519
+ background = patternFill
520
+ backgroundType = 'pattern'
521
+ }
522
+ }
393
523
  }
394
524
  else if (bgRef) {
395
525
  const phClr = getSolidFill(bgRef, clrMap, undefined, warpObj)
@@ -436,7 +566,7 @@ export async function getSlideBackgroundFill(warpObj) {
436
566
  const sldFill = bgFillLstIdx['a:solidFill']
437
567
  const sldBgClr = getSolidFill(sldFill, clrMapOvr, undefined, warpObj)
438
568
  background = sldBgClr
439
- }
569
+ }
440
570
  else if (bgFillTyp === 'GRADIENT_FILL') {
441
571
  const gradientFill = getBgGradientFill(bgFillLstIdx, phClr, slideMasterContent, warpObj)
442
572
  if (typeof gradientFill === 'string') {
@@ -451,6 +581,13 @@ export async function getSlideBackgroundFill(warpObj) {
451
581
  background = await getBgPicFill(bgFillLstIdx, 'themeBg', warpObj)
452
582
  backgroundType = 'image'
453
583
  }
584
+ else if (bgFillTyp === 'PATTERN_FILL') {
585
+ const patternFill = getPatternFill(bgFillLstIdx, warpObj)
586
+ if (patternFill) {
587
+ background = patternFill
588
+ backgroundType = 'pattern'
589
+ }
590
+ }
454
591
  }
455
592
  }
456
593
  }
@@ -488,6 +625,11 @@ export async function getShapeFill(node, pNode, isSvgMode, warpObj, source, grou
488
625
  }
489
626
  type = 'image'
490
627
  }
628
+ else if (fillType === 'PATTERN_FILL') {
629
+ const shpFill = node['p:spPr']['a:pattFill']
630
+ fillValue = getPatternFill({ 'a:pattFill': shpFill }, warpObj)
631
+ type = 'pattern'
632
+ }
491
633
  else if (fillType === 'GROUP_FILL') {
492
634
  return findFillInGroupHierarchy(groupHierarchy, warpObj, source)
493
635
  }
@@ -547,6 +689,16 @@ async function findFillInGroupHierarchy(groupHierarchy, warpObj, source) {
547
689
  }
548
690
  }
549
691
  }
692
+ else if (fillType === 'PATTERN_FILL') {
693
+ const shpFill = grpSpPr['a:pattFill']
694
+ const fillValue = getPatternFill({ 'a:pattFill': shpFill }, warpObj)
695
+ if (fillValue) {
696
+ return {
697
+ type: 'pattern',
698
+ value: fillValue,
699
+ }
700
+ }
701
+ }
550
702
  }
551
703
 
552
704
  return null
package/src/fontStyle.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getTextByPathList } from './utils'
2
2
  import { getShadow } from './shadow'
3
- import { getFillType, getSolidFill } from './fill'
3
+ import { getFillType, getGradientFill, getSolidFill } from './fill'
4
4
 
5
5
  export function getFontType(node, type, warpObj) {
6
6
  let typeface = getTextByPathList(node, ['a:rPr', 'a:latin', 'attrs', 'typeface'])
@@ -31,6 +31,11 @@ export function getFontColor(node, pNode, lstStyle, pFontStyle, lvl, warpObj) {
31
31
  const solidFillNode = rPrNode['a:solidFill']
32
32
  color = getSolidFill(solidFillNode, undefined, undefined, warpObj)
33
33
  }
34
+ if (filTyp === 'GRADIENT_FILL') {
35
+ const gradientFillNode = rPrNode['a:gradFill']
36
+ const gradient = getGradientFill(gradientFillNode, warpObj)
37
+ return gradient
38
+ }
34
39
  }
35
40
  if (!color && getTextByPathList(lstStyle, ['a:lvl' + lvl + 'pPr', 'a:defRPr'])) {
36
41
  const lstStyledefRPr = getTextByPathList(lstStyle, ['a:lvl' + lvl + 'pPr', 'a:defRPr'])
@@ -48,14 +53,49 @@ export function getFontColor(node, pNode, lstStyle, pFontStyle, lvl, warpObj) {
48
53
  return color || ''
49
54
  }
50
55
 
51
- export function getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles) {
56
+ export function getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles, textBodyNode, pNode) {
52
57
  let fontSize
53
58
 
54
59
  if (getTextByPathList(node, ['a:rPr', 'attrs', 'sz'])) fontSize = getTextByPathList(node, ['a:rPr', 'attrs', 'sz']) / 100
55
60
 
61
+ if ((isNaN(fontSize) || !fontSize) && pNode) {
62
+ if (getTextByPathList(pNode, ['a:endParaRPr', 'attrs', 'sz'])) {
63
+ fontSize = getTextByPathList(pNode, ['a:endParaRPr', 'attrs', 'sz']) / 100
64
+ }
65
+ }
66
+
67
+ if ((isNaN(fontSize) || !fontSize) && textBodyNode) {
68
+ const lstStyle = getTextByPathList(textBodyNode, ['a:lstStyle'])
69
+ if (lstStyle) {
70
+ let lvl = 1
71
+ if (pNode) {
72
+ const lvlNode = getTextByPathList(pNode, ['a:pPr', 'attrs', 'lvl'])
73
+ if (lvlNode !== undefined) lvl = parseInt(lvlNode) + 1
74
+ }
75
+
76
+ const sz = getTextByPathList(lstStyle, [`a:lvl${lvl}pPr`, 'a:defRPr', 'attrs', 'sz'])
77
+ if (sz) fontSize = parseInt(sz) / 100
78
+ }
79
+ }
80
+
56
81
  if ((isNaN(fontSize) || !fontSize)) {
57
82
  const sz = getTextByPathList(slideLayoutSpNode, ['p:txBody', 'a:lstStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz'])
58
- fontSize = parseInt(sz) / 100
83
+ if (sz) fontSize = parseInt(sz) / 100
84
+ }
85
+
86
+ if ((isNaN(fontSize) || !fontSize) && slideLayoutSpNode) {
87
+ let lvl = 1
88
+ if (pNode) {
89
+ const lvlNode = getTextByPathList(pNode, ['a:pPr', 'attrs', 'lvl'])
90
+ if (lvlNode !== undefined) lvl = parseInt(lvlNode) + 1
91
+ }
92
+ const layoutSz = getTextByPathList(slideLayoutSpNode, ['p:txBody', 'a:lstStyle', `a:lvl${lvl}pPr`, 'a:defRPr', 'attrs', 'sz'])
93
+ if (layoutSz) fontSize = parseInt(layoutSz) / 100
94
+ }
95
+
96
+ if ((isNaN(fontSize) || !fontSize) && pNode) {
97
+ const paraSz = getTextByPathList(pNode, ['a:pPr', 'a:defRPr', 'attrs', 'sz'])
98
+ if (paraSz) fontSize = parseInt(paraSz) / 100
59
99
  }
60
100
 
61
101
  if (isNaN(fontSize) || !fontSize) {
package/src/position.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { RATIO_EMUs_Points } from './constants'
2
+ import { numberToFixed } from './utils'
2
3
 
3
4
  export function getPosition(slideSpNode, slideLayoutSpNode, slideMasterSpNode) {
4
5
  let off
@@ -10,8 +11,8 @@ export function getPosition(slideSpNode, slideLayoutSpNode, slideMasterSpNode) {
10
11
  if (!off) return { top: 0, left: 0 }
11
12
 
12
13
  return {
13
- top: parseInt(off['y']) * RATIO_EMUs_Points,
14
- left: parseInt(off['x']) * RATIO_EMUs_Points,
14
+ top: numberToFixed(parseInt(off['y']) * RATIO_EMUs_Points),
15
+ left: numberToFixed(parseInt(off['x']) * RATIO_EMUs_Points),
15
16
  }
16
17
  }
17
18
 
@@ -25,7 +26,7 @@ export function getSize(slideSpNode, slideLayoutSpNode, slideMasterSpNode) {
25
26
  if (!ext) return { width: 0, height: 0 }
26
27
 
27
28
  return {
28
- width: parseInt(ext['cx']) * RATIO_EMUs_Points,
29
- height: parseInt(ext['cy']) * RATIO_EMUs_Points,
29
+ width: numberToFixed(parseInt(ext['cx']) * RATIO_EMUs_Points),
30
+ height: numberToFixed(parseInt(ext['cy']) * RATIO_EMUs_Points),
30
31
  }
31
32
  }
package/src/pptxtojson.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import JSZip from 'jszip'
2
2
  import { readXmlFile } from './readXmlFile'
3
3
  import { getBorder } from './border'
4
- import { getSlideBackgroundFill, getShapeFill, getSolidFill, getPicFill } from './fill'
4
+ import { getSlideBackgroundFill, getShapeFill, getSolidFill, getPicFill, getPicFilters } from './fill'
5
5
  import { getChartInfo } from './chart'
6
6
  import { getVerticalAlign } from './align'
7
7
  import { getPosition, getSize } from './position'
8
8
  import { genTextBody } from './text'
9
9
  import { getCustomShapePath } from './shape'
10
- import { extractFileExtension, base64ArrayBuffer, getTextByPathList, angleToDegrees, getMimeType, isVideoLink, escapeHtml, hasValidText } from './utils'
10
+ import { extractFileExtension, base64ArrayBuffer, getTextByPathList, angleToDegrees, getMimeType, isVideoLink, escapeHtml, hasValidText, numberToFixed } from './utils'
11
11
  import { getShadow } from './shadow'
12
12
  import { getTableBorders, getTableCellParams, getTableRowParams } from './table'
13
13
  import { RATIO_EMUs_Points } from './constants'
@@ -135,9 +135,17 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
135
135
  switch (relationshipArrayItem['attrs']['Type']) {
136
136
  case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout':
137
137
  layoutFilename = relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
138
+ slideResObj[relationshipArrayItem['attrs']['Id']] = {
139
+ type: relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
140
+ target: relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
141
+ }
138
142
  break
139
143
  case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide':
140
144
  noteFilename = relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
145
+ slideResObj[relationshipArrayItem['attrs']['Id']] = {
146
+ type: relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
147
+ target: relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
148
+ }
141
149
  break
142
150
  case 'http://schemas.microsoft.com/office/2007/relationships/diagramDrawing':
143
151
  diagramFilename = relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
@@ -508,20 +516,20 @@ async function processGroupSpNode(node, warpObj, source, parentGroupHierarchy =
508
516
 
509
517
  return {
510
518
  type: 'group',
511
- top: y,
512
- left: x,
513
- width: cx,
514
- height: cy,
519
+ top: numberToFixed(y),
520
+ left: numberToFixed(x),
521
+ width: numberToFixed(cx),
522
+ height: numberToFixed(cy),
515
523
  rotate,
516
524
  order,
517
525
  isFlipV,
518
526
  isFlipH,
519
527
  elements: elements.map(element => ({
520
528
  ...element,
521
- left: (element.left - chx) * ws,
522
- top: (element.top - chy) * hs,
523
- width: element.width * ws,
524
- height: element.height * hs,
529
+ left: numberToFixed((element.left - chx) * ws),
530
+ top: numberToFixed((element.top - chy) * hs),
531
+ width: numberToFixed(element.width * ws),
532
+ height: numberToFixed(element.height * hs),
525
533
  }))
526
534
  }
527
535
  }
@@ -794,11 +802,13 @@ async function processPicNode(node, warpObj, source) {
794
802
 
795
803
  const { borderColor, borderWidth, borderType, strokeDasharray } = getBorder(node, undefined, warpObj)
796
804
 
797
- return {
805
+ const filters = getPicFilters(node['p:blipFill'])
806
+
807
+ const imageData = {
798
808
  type: 'image',
799
809
  top,
800
810
  left,
801
- width,
811
+ width,
802
812
  height,
803
813
  rotate,
804
814
  src,
@@ -812,6 +822,10 @@ async function processPicNode(node, warpObj, source) {
812
822
  borderType,
813
823
  borderStrokeDasharray: strokeDasharray,
814
824
  }
825
+
826
+ if (filters) imageData.filters = filters
827
+
828
+ return imageData
815
829
  }
816
830
 
817
831
  async function processGraphicFrameNode(node, warpObj, source) {
package/src/text.js CHANGED
@@ -73,10 +73,39 @@ export function genTextBody(textBodyNode, spNode, slideLayoutSpNode, type, warpO
73
73
  text += `<p style="text-align: ${align};">`
74
74
  }
75
75
 
76
- if (!rNode) text += genSpanElement(pNode, spNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
76
+ if (!rNode) {
77
+ text += genSpanElement(pNode, spNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
78
+ }
77
79
  else {
80
+ let prevStyleInfo = null
81
+ let accumulatedText = ''
82
+
78
83
  for (const rNodeItem of rNode) {
79
- text += genSpanElement(rNodeItem, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
84
+ const styleInfo = getSpanStyleInfo(rNodeItem, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
85
+
86
+ if (!prevStyleInfo || prevStyleInfo.styleText !== styleInfo.styleText || prevStyleInfo.hasLink !== styleInfo.hasLink || styleInfo.hasLink) {
87
+ if (accumulatedText) {
88
+ const processedText = accumulatedText.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\s/g, '&nbsp;')
89
+ text += `<span style="${prevStyleInfo.styleText}">${processedText}</span>`
90
+ accumulatedText = ''
91
+ }
92
+
93
+ if (styleInfo.hasLink) {
94
+ const processedText = styleInfo.text.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\s/g, '&nbsp;')
95
+ text += `<span style="${styleInfo.styleText}"><a href="${styleInfo.linkURL}" target="_blank">${processedText}</a></span>`
96
+ prevStyleInfo = null
97
+ }
98
+ else {
99
+ prevStyleInfo = styleInfo
100
+ accumulatedText = styleInfo.text
101
+ }
102
+ }
103
+ else accumulatedText += styleInfo.text
104
+ }
105
+
106
+ if (accumulatedText && prevStyleInfo) {
107
+ const processedText = accumulatedText.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\s/g, '&nbsp;')
108
+ text += `<span style="${prevStyleInfo.styleText}">${processedText}</span>`
80
109
  }
81
110
  }
82
111
 
@@ -97,6 +126,16 @@ export function getListType(node) {
97
126
  }
98
127
 
99
128
  export function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj) {
129
+ const { styleText, text, hasLink, linkURL } = getSpanStyleInfo(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj)
130
+ const processedText = text.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\s/g, '&nbsp;')
131
+
132
+ if (hasLink) {
133
+ return `<span style="${styleText}"><a href="${linkURL}" target="_blank">${processedText}</a></span>`
134
+ }
135
+ return `<span style="${styleText}">${processedText}</span>`
136
+ }
137
+
138
+ export function getSpanStyleInfo(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj) {
100
139
  const lstStyle = textBodyNode['a:lstStyle']
101
140
  const slideMasterTextStyles = warpObj['slideMasterTextStyles']
102
141
 
@@ -111,7 +150,7 @@ export function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayou
111
150
 
112
151
  let styleText = ''
113
152
  const fontColor = getFontColor(node, pNode, lstStyle, pFontStyle, lvl, warpObj)
114
- const fontSize = getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles)
153
+ const fontSize = getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles, textBodyNode, pNode)
115
154
  const fontType = getFontType(node, type, warpObj)
116
155
  const fontBold = getFontBold(node)
117
156
  const fontItalic = getFontItalic(node)
@@ -121,7 +160,15 @@ export function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayou
121
160
  const shadow = getFontShadow(node, warpObj)
122
161
  const subscript = getFontSubscript(node)
123
162
 
124
- if (fontColor) styleText += `color: ${fontColor};`
163
+ if (fontColor) {
164
+ if (typeof fontColor === 'string') styleText += `color: ${fontColor};`
165
+ else if (fontColor.colors) {
166
+ const { colors, rot } = fontColor
167
+ const stops = colors.map(item => `${item.color} ${item.pos}`).join(', ')
168
+ const gradientStyle = `linear-gradient(${rot + 90}deg, ${stops})`
169
+ styleText += `background: ${gradientStyle}; background-clip: text; color: transparent;`
170
+ }
171
+ }
125
172
  if (fontSize) styleText += `font-size: ${fontSize};`
126
173
  if (fontType) styleText += `font-family: ${fontType};`
127
174
  if (fontBold) styleText += `font-weight: ${fontBold};`
@@ -133,9 +180,12 @@ export function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayou
133
180
  if (shadow) styleText += `text-shadow: ${shadow};`
134
181
 
135
182
  const linkID = getTextByPathList(node, ['a:rPr', 'a:hlinkClick', 'attrs', 'r:id'])
136
- if (linkID) {
137
- const linkURL = warpObj['slideResObj'][linkID]['target']
138
- return `<span style="${styleText}"><a href="${linkURL}" target="_blank">${text.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\s/g, '&nbsp;')}</a></span>`
139
- }
140
- return `<span style="${styleText}">${text.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;').replace(/\s/g, '&nbsp;')}</span>`
183
+ const hasLink = linkID && warpObj['slideResObj'][linkID]
184
+
185
+ return {
186
+ styleText,
187
+ text,
188
+ hasLink,
189
+ linkURL: hasLink ? warpObj['slideResObj'][linkID]['target'] : null
190
+ }
141
191
  }
package/src/utils.js CHANGED
@@ -160,4 +160,8 @@ export function hasValidText(htmlString) {
160
160
  const doc = parser.parseFromString(htmlString, 'text/html')
161
161
  const text = doc.body.textContent || doc.body.innerText
162
162
  return text.trim() !== ''
163
+ }
164
+
165
+ export function numberToFixed(num, fractionDigits = 4) {
166
+ return parseFloat(num.toFixed(fractionDigits))
163
167
  }