pptxtojson 2.0.3 → 2.0.5

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
@@ -432,11 +432,13 @@
432
432
  loadingOverlay.classList.add('show')
433
433
 
434
434
  try {
435
+ const parseStart = performance.now()
435
436
  const json = await pptxtojson.parse(e.target.result, {
436
437
  imageMode: 'both',
437
438
  videoMode: 'blob',
438
439
  audioMode: 'blob',
439
440
  })
441
+ console.log('parse time:', ((performance.now() - parseStart) / 1000).toFixed(3) + 's')
440
442
  editor.set(json)
441
443
  console.log(json)
442
444
  jsonString = JSON.stringify(json, null, 2)
@@ -459,7 +461,13 @@
459
461
  loadingOverlay.classList.add('show')
460
462
 
461
463
  try {
462
- const json = await pptxtojson.parse(file)
464
+ const parseStart = performance.now()
465
+ const json = await pptxtojson.parse(file, {
466
+ imageMode: 'both',
467
+ videoMode: 'blob',
468
+ audioMode: 'blob',
469
+ })
470
+ console.log('parse time:', ((performance.now() - parseStart) / 1000).toFixed(3) + 's')
463
471
  editor.set(json)
464
472
  console.log(json)
465
473
  jsonString = JSON.stringify(json, null, 2)
@@ -542,4 +550,4 @@
542
550
  })
543
551
  </script>
544
552
  </body>
545
- </html>
553
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptxtojson",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "A javascript tool for parsing .pptx file",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",
package/src/chart.js CHANGED
@@ -31,56 +31,66 @@ function extractChartData(serNode) {
31
31
  const dataMat = []
32
32
  if (!serNode) return dataMat
33
33
 
34
- if (serNode['c:xVal']) {
35
- let dataRow = []
36
- eachElement(serNode['c:xVal']['c:numRef']['c:numCache']['c:pt'], innerNode => {
37
- dataRow.push(parseFloat(innerNode['c:v']))
38
- return ''
39
- })
40
- dataMat.push(dataRow)
41
- dataRow = []
42
- eachElement(serNode['c:yVal']['c:numRef']['c:numCache']['c:pt'], innerNode => {
43
- dataRow.push(parseFloat(innerNode['c:v']))
44
- return ''
45
- })
46
- dataMat.push(dataRow)
47
- }
48
- else {
49
- eachElement(serNode, (innerNode, index) => {
50
- const dataRow = []
51
- const colName = getTextByPathList(innerNode, ['c:tx', 'c:strRef', 'c:strCache', 'c:pt', 'c:v']) || index
52
-
53
- const rowNames = {}
54
- if (getTextByPathList(innerNode, ['c:cat', 'c:strRef', 'c:strCache', 'c:pt'])) {
55
- eachElement(innerNode['c:cat']['c:strRef']['c:strCache']['c:pt'], innerNode => {
56
- rowNames[innerNode['attrs']['idx']] = innerNode['c:v']
57
- return ''
58
- })
59
- }
60
- else if (getTextByPathList(innerNode, ['c:cat', 'c:numRef', 'c:numCache', 'c:pt'])) {
61
- eachElement(innerNode['c:cat']['c:numRef']['c:numCache']['c:pt'], innerNode => {
62
- rowNames[innerNode['attrs']['idx']] = innerNode['c:v']
63
- return ''
64
- })
65
- }
34
+ eachElement(serNode, (innerNode, index) => {
35
+ const dataRow = []
36
+ const colName = getTextByPathList(innerNode, ['c:tx', 'c:strRef', 'c:strCache', 'c:pt', 'c:v']) || index
66
37
 
67
- if (getTextByPathList(innerNode, ['c:val', 'c:numRef', 'c:numCache', 'c:pt'])) {
68
- eachElement(innerNode['c:val']['c:numRef']['c:numCache']['c:pt'], innerNode => {
69
- dataRow.push({
70
- x: innerNode['attrs']['idx'],
71
- y: parseFloat(innerNode['c:v']),
72
- })
73
- return ''
74
- })
75
- }
38
+ const rowNames = {}
39
+ if (getTextByPathList(innerNode, ['c:cat', 'c:strRef', 'c:strCache', 'c:pt'])) {
40
+ eachElement(innerNode['c:cat']['c:strRef']['c:strCache']['c:pt'], innerNode => {
41
+ rowNames[innerNode['attrs']['idx']] = innerNode['c:v']
42
+ return ''
43
+ })
44
+ }
45
+ else if (getTextByPathList(innerNode, ['c:cat', 'c:numRef', 'c:numCache', 'c:pt'])) {
46
+ eachElement(innerNode['c:cat']['c:numRef']['c:numCache']['c:pt'], innerNode => {
47
+ rowNames[innerNode['attrs']['idx']] = innerNode['c:v']
48
+ return ''
49
+ })
50
+ }
76
51
 
77
- dataMat.push({
78
- key: colName,
79
- values: dataRow,
80
- xlabels: rowNames,
52
+ if (getTextByPathList(innerNode, ['c:val', 'c:numRef', 'c:numCache', 'c:pt'])) {
53
+ eachElement(innerNode['c:val']['c:numRef']['c:numCache']['c:pt'], innerNode => {
54
+ dataRow.push({
55
+ x: innerNode['attrs']['idx'],
56
+ y: parseFloat(innerNode['c:v']),
57
+ })
58
+ return ''
81
59
  })
60
+ }
61
+
62
+ dataMat.push({
63
+ key: colName,
64
+ values: dataRow,
65
+ xlabels: rowNames,
66
+ })
67
+ return ''
68
+ })
69
+
70
+ return dataMat
71
+ }
72
+
73
+ function extractScatterChartData(serNode) {
74
+ const dataMat = []
75
+ if (!serNode) return dataMat
76
+
77
+ const serNodes = serNode.constructor === Array ? serNode : [serNode]
78
+ const firstSerNode = serNodes[0]
79
+ const xData = []
80
+
81
+ eachElement(firstSerNode['c:xVal']['c:numRef']['c:numCache']['c:pt'], innerNode => {
82
+ xData.push(parseFloat(innerNode['c:v']))
83
+ return ''
84
+ })
85
+ dataMat.push(xData)
86
+
87
+ for (const node of serNodes) {
88
+ const yData = []
89
+ eachElement(node['c:yVal']['c:numRef']['c:numCache']['c:pt'], innerNode => {
90
+ yData.push(parseFloat(innerNode['c:v']))
82
91
  return ''
83
92
  })
93
+ dataMat.push(yData)
84
94
  }
85
95
 
86
96
  return dataMat
@@ -168,7 +178,7 @@ export function getChartInfo(plotArea, warpObj) {
168
178
  case 'c:scatterChart':
169
179
  chart = {
170
180
  type: 'scatterChart',
171
- data: extractChartData(plotArea[key]['c:ser']),
181
+ data: extractScatterChartData(plotArea[key]['c:ser']),
172
182
  colors: extractChartColors(plotArea[key]['c:ser'], warpObj),
173
183
  style: getTextByPathList(plotArea[key], ['c:scatterStyle', 'attrs', 'val']),
174
184
  }
@@ -176,7 +186,7 @@ export function getChartInfo(plotArea, warpObj) {
176
186
  case 'c:bubbleChart':
177
187
  chart = {
178
188
  type: 'bubbleChart',
179
- data: extractChartData(plotArea[key]['c:ser']),
189
+ data: extractScatterChartData(plotArea[key]['c:ser']),
180
190
  colors: extractChartColors(plotArea[key]['c:ser'], warpObj),
181
191
  }
182
192
  break
@@ -214,4 +224,4 @@ export function getChartInfo(plotArea, warpObj) {
214
224
  }
215
225
 
216
226
  return chart
217
- }
227
+ }
package/src/fill.js CHANGED
@@ -702,25 +702,47 @@ export async function getSlideBackgroundFill(warpObj) {
702
702
  }
703
703
  }
704
704
 
705
- export async function getShapeFill(node, warpObj, source, groupHierarchy = []) {
706
- const fillType = getFillType(getTextByPathList(node, ['p:spPr']))
705
+ function getShapeFillCandidates(node, source, slideLayoutSpNode, slideMasterSpNode) {
706
+ const candidates = [{ node, source }]
707
+
708
+ if (slideLayoutSpNode) {
709
+ candidates.push({
710
+ node: slideLayoutSpNode,
711
+ source: 'slideLayoutBg',
712
+ })
713
+ }
714
+ if (slideMasterSpNode) {
715
+ candidates.push({
716
+ node: slideMasterSpNode,
717
+ source: 'slideMasterBg',
718
+ })
719
+ }
720
+
721
+ return candidates
722
+ }
723
+
724
+ async function resolveShapeFillFromNode(node, warpObj, source, groupHierarchy) {
725
+ if (!node) return { state: 'missing' }
726
+
727
+ const spPr = getTextByPathList(node, ['p:spPr'])
728
+ const fillType = spPr ? getFillType(spPr) : ''
707
729
  let type = 'color'
708
730
  let fillValue = ''
709
731
  if (fillType === 'NO_FILL') {
710
- return null
732
+ return { state: 'none' }
711
733
  }
712
734
  else if (fillType === 'SOLID_FILL') {
713
- const shpFill = node['p:spPr']['a:solidFill']
735
+ const shpFill = spPr['a:solidFill']
714
736
  fillValue = getSolidFill(shpFill, undefined, undefined, warpObj)
715
737
  type = 'color'
716
738
  }
717
739
  else if (fillType === 'GRADIENT_FILL') {
718
- const shpFill = node['p:spPr']['a:gradFill']
740
+ const shpFill = spPr['a:gradFill']
719
741
  fillValue = getGradientFill(shpFill, warpObj)
720
742
  type = 'gradient'
721
743
  }
722
744
  else if (fillType === 'PIC_FILL') {
723
- const shpFill = node['p:spPr']['a:blipFill']
745
+ const shpFill = spPr['a:blipFill']
724
746
  const picFill = await getPicFill(source, shpFill, warpObj)
725
747
  const opacity = getPicFillOpacity(shpFill)
726
748
  fillValue = {
@@ -732,12 +754,13 @@ export async function getShapeFill(node, warpObj, source, groupHierarchy = []) {
732
754
  type = 'image'
733
755
  }
734
756
  else if (fillType === 'PATTERN_FILL') {
735
- const shpFill = node['p:spPr']['a:pattFill']
757
+ const shpFill = spPr['a:pattFill']
736
758
  fillValue = getPatternFill({ 'a:pattFill': shpFill }, warpObj)
737
759
  type = 'pattern'
738
760
  }
739
761
  else if (fillType === 'GROUP_FILL') {
740
- return findFillInGroupHierarchy(groupHierarchy, warpObj, source)
762
+ const groupFill = await findFillInGroupHierarchy(groupHierarchy, warpObj, source)
763
+ return groupFill ? { state: 'found', fill: groupFill } : { state: 'none' }
741
764
  }
742
765
  if (!fillValue) {
743
766
  const clrName = getTextByPathList(node, ['p:style', 'a:fillRef'])
@@ -745,15 +768,36 @@ export async function getShapeFill(node, warpObj, source, groupHierarchy = []) {
745
768
  type = 'color'
746
769
  }
747
770
  if (!fillValue) {
748
- return null
771
+ return { state: 'missing' }
749
772
  }
750
773
 
751
774
  return {
752
- type,
753
- value: fillValue,
775
+ state: 'found',
776
+ fill: {
777
+ type,
778
+ value: fillValue,
779
+ }
754
780
  }
755
781
  }
756
782
 
783
+ export async function getShapeFill(node, warpObj, source, options = {}) {
784
+ const {
785
+ groupHierarchy = [],
786
+ slideLayoutSpNode,
787
+ slideMasterSpNode,
788
+ } = options
789
+
790
+ const candidates = getShapeFillCandidates(node, source, slideLayoutSpNode, slideMasterSpNode)
791
+ for (const candidate of candidates) {
792
+ const result = await resolveShapeFillFromNode(candidate.node, warpObj, candidate.source, groupHierarchy)
793
+
794
+ if (result.state === 'none') return null
795
+ if (result.state === 'found') return result.fill
796
+ }
797
+
798
+ return null
799
+ }
800
+
757
801
  async function findFillInGroupHierarchy(groupHierarchy, warpObj, source) {
758
802
  for (const groupNode of groupHierarchy) {
759
803
  if (!groupNode || !groupNode['p:grpSpPr']) continue
@@ -892,4 +936,4 @@ export function getSolidFill(solidFill, clrMap, phClr, warpObj) {
892
936
  if (color && color.indexOf('#') === -1) color = '#' + color
893
937
 
894
938
  return color
895
- }
939
+ }
package/src/paragraph.js CHANGED
@@ -1,17 +1,18 @@
1
- import { getTextByPathList } from './utils'
2
-
3
- function getParagraphLevel(node) {
4
- let lvlIdx = 1
5
- const lvlNode = getTextByPathList(node, ['a:pPr', 'attrs', 'lvl'])
6
- if (lvlNode !== undefined) lvlIdx = parseInt(lvlNode) + 1
7
- return lvlIdx
8
- }
9
-
10
- function getAlignFromTextNode(node, lvlStr) {
11
- if (!node) return ''
12
-
13
- let algn = getTextByPathList(node, ['p:txBody', 'a:lstStyle', lvlStr, 'attrs', 'algn'])
14
- if (!algn) algn = getTextByPathList(node, ['p:txBody', 'a:p', 'a:pPr', 'attrs', 'algn'])
1
+ import { RATIO_EMUs_Points } from './constants'
2
+ import { getTextByPathList, numberToFixed } from './utils'
3
+
4
+ function getParagraphLevel(node) {
5
+ let lvlIdx = 1
6
+ const lvlNode = getTextByPathList(node, ['a:pPr', 'attrs', 'lvl'])
7
+ if (lvlNode !== undefined) lvlIdx = parseInt(lvlNode) + 1
8
+ return lvlIdx
9
+ }
10
+
11
+ function getAlignFromTextNode(node, lvlStr) {
12
+ if (!node) return ''
13
+
14
+ let algn = getTextByPathList(node, ['p:txBody', 'a:lstStyle', lvlStr, 'attrs', 'algn'])
15
+ if (!algn) algn = getTextByPathList(node, ['p:txBody', 'a:p', 'a:pPr', 'attrs', 'algn'])
15
16
 
16
17
  return algn || ''
17
18
  }
@@ -109,115 +110,144 @@ export function getTextAutoFit(node, slideLayoutSpNode, slideMasterSpNode) {
109
110
 
110
111
  const masterCheck = checkBodyPr(getTextByPathList(slideMasterSpNode, ['p:txBody', 'a:bodyPr']))
111
112
  if (masterCheck) return masterCheck.result
112
-
113
- return null
114
- }
115
-
116
- function pushParagraphStyleNode(styleNodes, styleNode) {
117
- if (styleNode) styleNodes.push(styleNode)
118
- }
119
-
120
- function appendTextBodyParagraphStyleNodes(styleNodes, textBodyNode, lvl) {
121
- if (!textBodyNode) return
122
-
123
- const lvlPath = `a:lvl${lvl}pPr`
124
- pushParagraphStyleNode(styleNodes, getTextByPathList(textBodyNode, ['a:lstStyle', lvlPath]))
125
- }
126
-
127
- function appendShapeParagraphStyleNodes(styleNodes, shapeNode, lvl) {
128
- if (!shapeNode) return
129
-
130
- const lvlPath = `a:lvl${lvl}pPr`
131
- pushParagraphStyleNode(styleNodes, getTextByPathList(shapeNode, ['p:txBody', 'a:lstStyle', lvlPath]))
132
- pushParagraphStyleNode(styleNodes, getTextByPathList(shapeNode, ['p:txBody', 'a:p', 'a:pPr']))
133
- }
134
-
135
- function appendMasterTextParagraphStyleNodes(styleNodes, type, lvl, slideMasterTextStyles) {
136
- if (!slideMasterTextStyles) return
137
-
138
- const lvlPath = `a:lvl${lvl}pPr`
139
-
140
- if (type === 'title' || type === 'ctrTitle' || type === 'subTitle') {
141
- pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:titleStyle', lvlPath]))
142
- if (type === 'subTitle') {
143
- pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:bodyStyle', lvlPath]))
144
- }
145
- }
146
- else if (type === 'body') {
147
- pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:bodyStyle', lvlPath]))
148
- }
149
- else {
150
- pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:otherStyle', lvlPath]))
151
- }
152
- }
153
-
154
- function appendDefaultTextParagraphStyleNodes(styleNodes, defaultTextStyle, lvl) {
155
- if (!defaultTextStyle) return
156
-
157
- const lvlPath = `a:lvl${lvl}pPr`
158
- pushParagraphStyleNode(styleNodes, getTextByPathList(defaultTextStyle, [lvlPath]))
159
- pushParagraphStyleNode(styleNodes, getTextByPathList(defaultTextStyle, ['a:defPPr']))
160
- }
161
-
162
- function getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
163
- if (!pNode) return null
164
-
165
- const pPrNode = pNode['a:pPr']
166
- const lvl = getParagraphLevel(pNode)
167
- const styleNodes = []
168
-
169
- pushParagraphStyleNode(styleNodes, pPrNode)
170
- appendTextBodyParagraphStyleNodes(styleNodes, textBodyNode, lvl)
171
- appendShapeParagraphStyleNodes(styleNodes, slideLayoutSpNode, lvl)
172
- appendShapeParagraphStyleNodes(styleNodes, slideMasterSpNode, lvl)
173
- appendMasterTextParagraphStyleNodes(styleNodes, type, lvl, slideMasterTextStyles)
174
- appendDefaultTextParagraphStyleNodes(styleNodes, getTextByPathList(warpObj, ['defaultTextStyle']), lvl)
175
-
176
- return styleNodes
177
- }
178
-
179
- function getLineSpacingValue(spacingNode) {
180
- const spcPct = getTextByPathList(spacingNode, ['a:spcPct', 'attrs', 'val'])
181
- const spcPts = getTextByPathList(spacingNode, ['a:spcPts', 'attrs', 'val'])
182
-
183
- if (spcPct) return parseInt(spcPct) / 1000 / 100
184
- if (spcPts) return parseInt(spcPts) / 100 + 'pt'
185
-
186
- return undefined
187
- }
188
-
189
- function getParagraphSpacingValue(spacingNode) {
190
- const spcPct = getTextByPathList(spacingNode, ['a:spcPct', 'attrs', 'val'])
191
- const spcPts = getTextByPathList(spacingNode, ['a:spcPts', 'attrs', 'val'])
192
-
193
- if (spcPct) return parseInt(spcPct) / 1000 + 'em'
194
- if (spcPts) return parseInt(spcPts) / 100 + 'pt'
195
-
196
- return undefined
197
- }
198
-
199
- export function getParagraphSpacing(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
200
- const styleNodes = getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj)
201
- if (!styleNodes) return null
202
-
203
- const spacing = {}
204
-
205
- for (const styleNode of styleNodes) {
206
- if (spacing.lineSpacing === undefined) {
207
- const lineSpacing = getLineSpacingValue(styleNode['a:lnSpc'])
208
- if (lineSpacing !== undefined) spacing.lineSpacing = lineSpacing
209
- }
210
-
211
- if (spacing.spaceBefore === undefined) {
212
- const spaceBefore = getParagraphSpacingValue(styleNode['a:spcBef'])
213
- if (spaceBefore !== undefined) spacing.spaceBefore = spaceBefore
214
- }
215
-
216
- if (spacing.spaceAfter === undefined) {
217
- const spaceAfter = getParagraphSpacingValue(styleNode['a:spcAft'])
218
- if (spaceAfter !== undefined) spacing.spaceAfter = spaceAfter
219
- }
220
- }
221
-
222
- return Object.keys(spacing).length > 0 ? spacing : null
223
- }
113
+
114
+ return null
115
+ }
116
+
117
+ function pushParagraphStyleNode(styleNodes, styleNode) {
118
+ if (styleNode) styleNodes.push(styleNode)
119
+ }
120
+
121
+ function appendTextBodyParagraphStyleNodes(styleNodes, textBodyNode, lvl) {
122
+ if (!textBodyNode) return
123
+
124
+ const lvlPath = `a:lvl${lvl}pPr`
125
+ pushParagraphStyleNode(styleNodes, getTextByPathList(textBodyNode, ['a:lstStyle', lvlPath]))
126
+ }
127
+
128
+ function appendShapeParagraphStyleNodes(styleNodes, shapeNode, lvl) {
129
+ if (!shapeNode) return
130
+
131
+ const lvlPath = `a:lvl${lvl}pPr`
132
+ pushParagraphStyleNode(styleNodes, getTextByPathList(shapeNode, ['p:txBody', 'a:lstStyle', lvlPath]))
133
+ pushParagraphStyleNode(styleNodes, getTextByPathList(shapeNode, ['p:txBody', 'a:p', 'a:pPr']))
134
+ }
135
+
136
+ function appendMasterTextParagraphStyleNodes(styleNodes, type, lvl, slideMasterTextStyles) {
137
+ if (!slideMasterTextStyles) return
138
+
139
+ const lvlPath = `a:lvl${lvl}pPr`
140
+
141
+ if (type === 'title' || type === 'ctrTitle' || type === 'subTitle') {
142
+ pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:titleStyle', lvlPath]))
143
+ if (type === 'subTitle') {
144
+ pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:bodyStyle', lvlPath]))
145
+ }
146
+ }
147
+ else if (type === 'body') {
148
+ pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:bodyStyle', lvlPath]))
149
+ }
150
+ else {
151
+ pushParagraphStyleNode(styleNodes, getTextByPathList(slideMasterTextStyles, ['p:otherStyle', lvlPath]))
152
+ }
153
+ }
154
+
155
+ function appendDefaultTextParagraphStyleNodes(styleNodes, defaultTextStyle, lvl) {
156
+ if (!defaultTextStyle) return
157
+
158
+ const lvlPath = `a:lvl${lvl}pPr`
159
+ pushParagraphStyleNode(styleNodes, getTextByPathList(defaultTextStyle, [lvlPath]))
160
+ pushParagraphStyleNode(styleNodes, getTextByPathList(defaultTextStyle, ['a:defPPr']))
161
+ }
162
+
163
+ function getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
164
+ if (!pNode) return null
165
+
166
+ const pPrNode = pNode['a:pPr']
167
+ const lvl = getParagraphLevel(pNode)
168
+ const styleNodes = []
169
+
170
+ pushParagraphStyleNode(styleNodes, pPrNode)
171
+ appendTextBodyParagraphStyleNodes(styleNodes, textBodyNode, lvl)
172
+ appendShapeParagraphStyleNodes(styleNodes, slideLayoutSpNode, lvl)
173
+ appendShapeParagraphStyleNodes(styleNodes, slideMasterSpNode, lvl)
174
+ appendMasterTextParagraphStyleNodes(styleNodes, type, lvl, slideMasterTextStyles)
175
+ appendDefaultTextParagraphStyleNodes(styleNodes, getTextByPathList(warpObj, ['defaultTextStyle']), lvl)
176
+
177
+ return styleNodes
178
+ }
179
+
180
+ function getLineSpacingValue(spacingNode) {
181
+ const spcPct = getTextByPathList(spacingNode, ['a:spcPct', 'attrs', 'val'])
182
+ const spcPts = getTextByPathList(spacingNode, ['a:spcPts', 'attrs', 'val'])
183
+
184
+ if (spcPct) return parseInt(spcPct) / 1000 / 100
185
+ if (spcPts) return parseInt(spcPts) / 100 + 'pt'
186
+
187
+ return undefined
188
+ }
189
+
190
+ function getParagraphSpacingValue(spacingNode) {
191
+ const spcPct = getTextByPathList(spacingNode, ['a:spcPct', 'attrs', 'val'])
192
+ const spcPts = getTextByPathList(spacingNode, ['a:spcPts', 'attrs', 'val'])
193
+
194
+ if (spcPct) return parseInt(spcPct) / 1000 + 'em'
195
+ if (spcPts) return parseInt(spcPts) / 100 + 'pt'
196
+
197
+ return undefined
198
+ }
199
+
200
+ function getParagraphIndentValue(styleNode, attrName) {
201
+ const val = getTextByPathList(styleNode, ['attrs', attrName])
202
+
203
+ if (val !== undefined && val !== '') return numberToFixed(parseInt(val) * RATIO_EMUs_Points) + 'pt'
204
+
205
+ return undefined
206
+ }
207
+
208
+ export function getParagraphSpacing(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
209
+ const styleNodes = getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj)
210
+ if (!styleNodes) return null
211
+
212
+ const spacing = {}
213
+
214
+ for (const styleNode of styleNodes) {
215
+ if (spacing.lineSpacing === undefined) {
216
+ const lineSpacing = getLineSpacingValue(styleNode['a:lnSpc'])
217
+ if (lineSpacing !== undefined) spacing.lineSpacing = lineSpacing
218
+ }
219
+
220
+ if (spacing.spaceBefore === undefined) {
221
+ const spaceBefore = getParagraphSpacingValue(styleNode['a:spcBef'])
222
+ if (spaceBefore !== undefined) spacing.spaceBefore = spaceBefore
223
+ }
224
+
225
+ if (spacing.spaceAfter === undefined) {
226
+ const spaceAfter = getParagraphSpacingValue(styleNode['a:spcAft'])
227
+ if (spaceAfter !== undefined) spacing.spaceAfter = spaceAfter
228
+ }
229
+ }
230
+
231
+ return Object.keys(spacing).length > 0 ? spacing : null
232
+ }
233
+
234
+ export function getParagraphIndent(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
235
+ const styleNodes = getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj)
236
+ if (!styleNodes) return null
237
+
238
+ const indent = {}
239
+
240
+ for (const styleNode of styleNodes) {
241
+ if (indent.marginLeft === undefined) {
242
+ const marginLeft = getParagraphIndentValue(styleNode, 'marL')
243
+ if (marginLeft !== undefined) indent.marginLeft = marginLeft
244
+ }
245
+
246
+ if (indent.textIndent === undefined) {
247
+ const textIndent = getParagraphIndentValue(styleNode, 'indent')
248
+ if (textIndent !== undefined) indent.textIndent = textIndent
249
+ }
250
+ }
251
+
252
+ return Object.keys(indent).length > 0 ? indent : null
253
+ }