pptxtojson 0.0.13 → 0.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/README.md +9 -6
- package/dist/index.d.ts +67 -8
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/index.html +4 -1
- package/package.json +2 -2
- package/src/align.js +36 -0
- package/src/border.js +95 -0
- package/src/chart.js +173 -0
- package/src/color.js +168 -0
- package/src/fill.js +330 -0
- package/src/fontStyle.js +105 -0
- package/src/position.js +29 -0
- package/src/pptxtojson.js +248 -1070
- package/src/readXmlFile.js +41 -0
- package/src/schemeColor.js +24 -0
- package/src/shadow.js +18 -0
- package/src/shape.js +178 -0
- package/src/text.js +131 -0
- package/src/utils.js +16 -3
- package/test.pptx +0 -0
- package/test2.pptx +0 -0
- package/test3.pptx +0 -0
package/src/pptxtojson.js
CHANGED
|
@@ -1,76 +1,49 @@
|
|
|
1
1
|
import JSZip from 'jszip'
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import { readXmlFile } from './readXmlFile'
|
|
3
|
+
import { getBorder } from './border'
|
|
4
|
+
import { getSlideBackgroundFill, getShapeFill } from './fill'
|
|
5
|
+
import { getChartInfo } from './chart'
|
|
6
|
+
import { getVerticalAlign } from './align'
|
|
7
|
+
import { getPosition, getSize } from './position'
|
|
8
|
+
import { genTextBody } from './text'
|
|
9
|
+
import { getCustomShapePath } from './shape'
|
|
10
|
+
import { extractFileExtension, base64ArrayBuffer, getTextByPathList, angleToDegrees, getMimeType, isVideoLink, escapeHtml } from './utils'
|
|
11
|
+
import { getShadow } from './shadow'
|
|
4
12
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
base64ArrayBuffer,
|
|
8
|
-
eachElement,
|
|
9
|
-
getTextByPathList,
|
|
10
|
-
angleToDegrees,
|
|
11
|
-
escapeHtml,
|
|
12
|
-
getMimeType,
|
|
13
|
-
} from './utils'
|
|
13
|
+
let SLIDE_FACTOR = 96 / 914400
|
|
14
|
+
let FONTSIZE_FACTOR = 100 / 75
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
+
const defaultOptions = {
|
|
17
|
+
slideFactor: SLIDE_FACTOR,
|
|
18
|
+
fontsizeFactor: FONTSIZE_FACTOR,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function parse(file, options = {}) {
|
|
22
|
+
options = { ...defaultOptions, ...options }
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
if (options.slideFactor) SLIDE_FACTOR = options.slideFactor
|
|
25
|
+
if (options.fontsizeFactor) FONTSIZE_FACTOR = options.fontsizeFactor
|
|
19
26
|
|
|
20
|
-
export async function parse(file) {
|
|
21
27
|
const slides = []
|
|
22
28
|
|
|
23
29
|
const zip = await JSZip.loadAsync(file)
|
|
24
30
|
|
|
25
31
|
const filesInfo = await getContentTypes(zip)
|
|
26
|
-
const { width, height, defaultTextStyle
|
|
27
|
-
themeContent = await loadTheme(zip)
|
|
28
|
-
defaultTextStyle = _defaultTextStyle
|
|
32
|
+
const { width, height, defaultTextStyle } = await getSlideInfo(zip)
|
|
33
|
+
const themeContent = await loadTheme(zip)
|
|
29
34
|
|
|
30
35
|
for (const filename of filesInfo.slides) {
|
|
31
|
-
const singleSlide = await processSingleSlide(zip, filename)
|
|
36
|
+
const singleSlide = await processSingleSlide(zip, filename, themeContent, defaultTextStyle)
|
|
32
37
|
slides.push(singleSlide)
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
return {
|
|
36
41
|
slides,
|
|
37
|
-
size: {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function simplifyLostLess(children, parentAttributes = {}) {
|
|
42
|
-
const out = {}
|
|
43
|
-
if (!children.length) return out
|
|
44
|
-
|
|
45
|
-
if (children.length === 1 && typeof children[0] === 'string') {
|
|
46
|
-
return Object.keys(parentAttributes).length ? {
|
|
47
|
-
attrs: parentAttributes,
|
|
48
|
-
value: children[0],
|
|
49
|
-
} : children[0]
|
|
50
|
-
}
|
|
51
|
-
for (const child of children) {
|
|
52
|
-
if (typeof child !== 'object') return
|
|
53
|
-
if (child.tagName === '?xml') continue
|
|
54
|
-
|
|
55
|
-
if (!out[child.tagName]) out[child.tagName] = []
|
|
56
|
-
|
|
57
|
-
const kids = simplifyLostLess(child.children || [], child.attributes)
|
|
58
|
-
out[child.tagName].push(kids)
|
|
59
|
-
|
|
60
|
-
if (Object.keys(child.attributes).length) {
|
|
61
|
-
kids.attrs = child.attributes
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
for (const child in out) {
|
|
65
|
-
if (out[child].length === 1) out[child] = out[child][0]
|
|
42
|
+
size: {
|
|
43
|
+
width,
|
|
44
|
+
height,
|
|
45
|
+
},
|
|
66
46
|
}
|
|
67
|
-
|
|
68
|
-
return out
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function readXmlFile(zip, filename) {
|
|
72
|
-
const data = await zip.file(filename).async('string')
|
|
73
|
-
return simplifyLostLess(txml.parse(data))
|
|
74
47
|
}
|
|
75
48
|
|
|
76
49
|
async function getContentTypes(zip) {
|
|
@@ -105,13 +78,13 @@ async function getContentTypes(zip) {
|
|
|
105
78
|
}
|
|
106
79
|
}
|
|
107
80
|
|
|
108
|
-
async function
|
|
81
|
+
async function getSlideInfo(zip) {
|
|
109
82
|
const content = await readXmlFile(zip, 'ppt/presentation.xml')
|
|
110
83
|
const sldSzAttrs = content['p:presentation']['p:sldSz']['attrs']
|
|
111
84
|
const defaultTextStyle = content['p:presentation']['p:defaultTextStyle']
|
|
112
85
|
return {
|
|
113
|
-
width: parseInt(sldSzAttrs['cx']) *
|
|
114
|
-
height: parseInt(sldSzAttrs['cy']) *
|
|
86
|
+
width: parseInt(sldSzAttrs['cx']) * SLIDE_FACTOR,
|
|
87
|
+
height: parseInt(sldSzAttrs['cy']) * SLIDE_FACTOR,
|
|
115
88
|
defaultTextStyle,
|
|
116
89
|
}
|
|
117
90
|
}
|
|
@@ -132,17 +105,17 @@ async function loadTheme(zip) {
|
|
|
132
105
|
else if (relationshipArray['attrs']['Type'] === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme') {
|
|
133
106
|
themeURI = relationshipArray['attrs']['Target']
|
|
134
107
|
}
|
|
135
|
-
|
|
136
108
|
if (!themeURI) throw Error(`Can't open theme file.`)
|
|
137
109
|
|
|
138
110
|
return await readXmlFile(zip, 'ppt/' + themeURI)
|
|
139
111
|
}
|
|
140
112
|
|
|
141
|
-
async function processSingleSlide(zip, sldFileName) {
|
|
113
|
+
async function processSingleSlide(zip, sldFileName, themeContent, defaultTextStyle) {
|
|
142
114
|
const resName = sldFileName.replace('slides/slide', 'slides/_rels/slide') + '.rels'
|
|
143
115
|
const resContent = await readXmlFile(zip, resName)
|
|
144
116
|
let relationshipArray = resContent['Relationships']['Relationship']
|
|
145
117
|
let layoutFilename = ''
|
|
118
|
+
let diagramFilename = ''
|
|
146
119
|
const slideResObj = {}
|
|
147
120
|
|
|
148
121
|
if (relationshipArray.constructor === Array) {
|
|
@@ -152,6 +125,7 @@ async function processSingleSlide(zip, sldFileName) {
|
|
|
152
125
|
layoutFilename = relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
|
|
153
126
|
break
|
|
154
127
|
case 'http://schemas.microsoft.com/office/2007/relationships/diagramDrawing':
|
|
128
|
+
diagramFilename = relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
|
|
155
129
|
slideResObj[relationshipArrayItem['attrs']['Id']] = {
|
|
156
130
|
type: relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
|
|
157
131
|
target: relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
|
|
@@ -219,9 +193,7 @@ async function processSingleSlide(zip, sldFileName) {
|
|
|
219
193
|
}
|
|
220
194
|
}
|
|
221
195
|
}
|
|
222
|
-
else
|
|
223
|
-
themeFilename = relationshipArray['attrs']['Target'].replace('../', 'ppt/')
|
|
224
|
-
}
|
|
196
|
+
else themeFilename = relationshipArray['attrs']['Target'].replace('../', 'ppt/')
|
|
225
197
|
|
|
226
198
|
const themeResObj = {}
|
|
227
199
|
if (themeFilename) {
|
|
@@ -249,6 +221,37 @@ async function processSingleSlide(zip, sldFileName) {
|
|
|
249
221
|
}
|
|
250
222
|
}
|
|
251
223
|
|
|
224
|
+
const diagramResObj = {}
|
|
225
|
+
let digramFileContent = {}
|
|
226
|
+
if (diagramFilename) {
|
|
227
|
+
const diagName = diagramFilename.split('/').pop()
|
|
228
|
+
const diagramResFileName = diagramFilename.replace(diagName, '_rels/' + diagName) + '.rels'
|
|
229
|
+
digramFileContent = await readXmlFile(zip, diagramFilename)
|
|
230
|
+
if (digramFileContent && digramFileContent && digramFileContent) {
|
|
231
|
+
let digramFileContentObjToStr = JSON.stringify(digramFileContent)
|
|
232
|
+
digramFileContentObjToStr = digramFileContentObjToStr.replace(/dsp:/g, 'p:')
|
|
233
|
+
digramFileContent = JSON.parse(digramFileContentObjToStr)
|
|
234
|
+
}
|
|
235
|
+
const digramResContent = await readXmlFile(zip, diagramResFileName)
|
|
236
|
+
if (digramResContent) {
|
|
237
|
+
relationshipArray = digramResContent['Relationships']['Relationship']
|
|
238
|
+
if (relationshipArray.constructor === Array) {
|
|
239
|
+
for (const relationshipArrayItem of relationshipArray) {
|
|
240
|
+
diagramResObj[relationshipArrayItem['attrs']['Id']] = {
|
|
241
|
+
'type': relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
|
|
242
|
+
'target': relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
diagramResObj[relationshipArray['attrs']['Id']] = {
|
|
248
|
+
'type': relationshipArray['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
|
|
249
|
+
'target': relationshipArray['attrs']['Target'].replace('../', 'ppt/')
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
252
255
|
const slideContent = await readXmlFile(zip, sldFileName)
|
|
253
256
|
const nodes = slideContent['p:sld']['p:cSld']['p:spTree']
|
|
254
257
|
const warpObj = {
|
|
@@ -264,6 +267,8 @@ async function processSingleSlide(zip, sldFileName) {
|
|
|
264
267
|
masterResObj: masterResObj,
|
|
265
268
|
themeContent: themeContent,
|
|
266
269
|
themeResObj: themeResObj,
|
|
270
|
+
digramFileContent: digramFileContent,
|
|
271
|
+
diagramResObj: diagramResObj,
|
|
267
272
|
defaultTextStyle: defaultTextStyle,
|
|
268
273
|
}
|
|
269
274
|
const bgColor = await getSlideBackgroundFill(warpObj)
|
|
@@ -289,10 +294,8 @@ async function processSingleSlide(zip, sldFileName) {
|
|
|
289
294
|
}
|
|
290
295
|
|
|
291
296
|
function indexNodes(content) {
|
|
292
|
-
|
|
293
297
|
const keys = Object.keys(content)
|
|
294
298
|
const spTreeNode = content[keys[0]]['p:cSld']['p:spTree']
|
|
295
|
-
|
|
296
299
|
const idTable = {}
|
|
297
300
|
const idxTable = {}
|
|
298
301
|
const typeTable = {}
|
|
@@ -336,10 +339,10 @@ async function processNodesInSlide(nodeKey, nodeValue, warpObj) {
|
|
|
336
339
|
case 'p:sp': // Shape, Text
|
|
337
340
|
json = processSpNode(nodeValue, warpObj)
|
|
338
341
|
break
|
|
339
|
-
case 'p:cxnSp': // Shape, Text
|
|
342
|
+
case 'p:cxnSp': // Shape, Text
|
|
340
343
|
json = processCxnSpNode(nodeValue, warpObj)
|
|
341
344
|
break
|
|
342
|
-
case 'p:pic': //
|
|
345
|
+
case 'p:pic': // Image, Video, Audio
|
|
343
346
|
json = processPicNode(nodeValue, warpObj)
|
|
344
347
|
break
|
|
345
348
|
case 'p:graphicFrame': // Chart, Diagram, Table
|
|
@@ -358,15 +361,17 @@ async function processNodesInSlide(nodeKey, nodeValue, warpObj) {
|
|
|
358
361
|
}
|
|
359
362
|
|
|
360
363
|
async function processGroupSpNode(node, warpObj) {
|
|
361
|
-
const xfrmNode = node['p:grpSpPr'
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
const
|
|
364
|
+
const xfrmNode = getTextByPathList(node, ['p:grpSpPr', 'a:xfrm'])
|
|
365
|
+
if (!xfrmNode) return null
|
|
366
|
+
|
|
367
|
+
const x = parseInt(xfrmNode['a:off']['attrs']['x']) * SLIDE_FACTOR
|
|
368
|
+
const y = parseInt(xfrmNode['a:off']['attrs']['y']) * SLIDE_FACTOR
|
|
369
|
+
const chx = parseInt(xfrmNode['a:chOff']['attrs']['x']) * SLIDE_FACTOR
|
|
370
|
+
const chy = parseInt(xfrmNode['a:chOff']['attrs']['y']) * SLIDE_FACTOR
|
|
371
|
+
const cx = parseInt(xfrmNode['a:ext']['attrs']['cx']) * SLIDE_FACTOR
|
|
372
|
+
const cy = parseInt(xfrmNode['a:ext']['attrs']['cy']) * SLIDE_FACTOR
|
|
373
|
+
const chcx = parseInt(xfrmNode['a:chExt']['attrs']['cx']) * SLIDE_FACTOR
|
|
374
|
+
const chcy = parseInt(xfrmNode['a:chExt']['attrs']['cy']) * SLIDE_FACTOR
|
|
370
375
|
|
|
371
376
|
const elements = []
|
|
372
377
|
for (const nodeKey in node) {
|
|
@@ -392,11 +397,11 @@ async function processGroupSpNode(node, warpObj) {
|
|
|
392
397
|
}
|
|
393
398
|
}
|
|
394
399
|
|
|
395
|
-
function processSpNode(node, warpObj) {
|
|
396
|
-
const id = node['p:nvSpPr'
|
|
397
|
-
const name = node['p:nvSpPr'
|
|
398
|
-
const idx = node['p:nvSpPr'
|
|
399
|
-
let type = node['p:nvSpPr'
|
|
400
|
+
function processSpNode(node, warpObj, source) {
|
|
401
|
+
const id = getTextByPathList(node, ['p:nvSpPr', 'p:cNvPr', 'attrs', 'id'])
|
|
402
|
+
const name = getTextByPathList(node, ['p:nvSpPr', 'p:cNvPr', 'attrs', 'name'])
|
|
403
|
+
const idx = getTextByPathList(node, ['p:nvSpPr', 'p:nvPr', 'p:ph', 'attrs', 'idx'])
|
|
404
|
+
let type = getTextByPathList(node, ['p:nvSpPr', 'p:nvPr', 'p:ph', 'attrs', 'type'])
|
|
400
405
|
|
|
401
406
|
let slideLayoutSpNode, slideMasterSpNode
|
|
402
407
|
|
|
@@ -422,6 +427,11 @@ function processSpNode(node, warpObj) {
|
|
|
422
427
|
if (!type) type = getTextByPathList(slideLayoutSpNode, ['p:nvSpPr', 'p:nvPr', 'p:ph', 'attrs', 'type'])
|
|
423
428
|
if (!type) type = getTextByPathList(slideMasterSpNode, ['p:nvSpPr', 'p:nvPr', 'p:ph', 'attrs', 'type'])
|
|
424
429
|
|
|
430
|
+
if (!type) {
|
|
431
|
+
if (source === 'diagramBg') type = 'diagram'
|
|
432
|
+
else type = 'obj'
|
|
433
|
+
}
|
|
434
|
+
|
|
425
435
|
return genShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, warpObj)
|
|
426
436
|
}
|
|
427
437
|
|
|
@@ -434,51 +444,6 @@ function processCxnSpNode(node, warpObj) {
|
|
|
434
444
|
return genShape(node, undefined, undefined, id, name, idx, type, warpObj)
|
|
435
445
|
}
|
|
436
446
|
|
|
437
|
-
function shapeArc(cX, cY, rX, rY, stAng, endAng, isClose) {
|
|
438
|
-
let dData
|
|
439
|
-
let angle = stAng
|
|
440
|
-
if (endAng >= stAng) {
|
|
441
|
-
while (angle <= endAng) {
|
|
442
|
-
const radians = angle * (Math.PI / 180)
|
|
443
|
-
const x = cX + Math.cos(radians) * rX
|
|
444
|
-
const y = cY + Math.sin(radians) * rY
|
|
445
|
-
if (angle === stAng) {
|
|
446
|
-
dData = ' M' + x + ' ' + y
|
|
447
|
-
}
|
|
448
|
-
dData += ' L' + x + ' ' + y
|
|
449
|
-
angle++
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
while (angle > endAng) {
|
|
454
|
-
const radians = angle * (Math.PI / 180)
|
|
455
|
-
const x = cX + Math.cos(radians) * rX
|
|
456
|
-
const y = cY + Math.sin(radians) * rY
|
|
457
|
-
if (angle === stAng) {
|
|
458
|
-
dData = ' M ' + x + ' ' + y
|
|
459
|
-
}
|
|
460
|
-
dData += ' L ' + x + ' ' + y
|
|
461
|
-
angle--
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
dData += (isClose ? ' z' : '')
|
|
465
|
-
return dData
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function getVerticalAlign(node, slideLayoutSpNode, slideMasterSpNode) {
|
|
469
|
-
let anchor = getTextByPathList(node, ['p:txBody', 'a:bodyPr', 'attrs', 'anchor'])
|
|
470
|
-
if (anchor) {
|
|
471
|
-
anchor = getTextByPathList(slideLayoutSpNode, ['p:txBody', 'a:bodyPr', 'attrs', 'anchor'])
|
|
472
|
-
if (anchor) {
|
|
473
|
-
anchor = getTextByPathList(slideMasterSpNode, ['p:txBody', 'a:bodyPr', 'attrs', 'anchor'])
|
|
474
|
-
if (anchor) {
|
|
475
|
-
anchor = 't'
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
return (anchor === 'ctr') ? 'mid' : ((anchor === 'b') ? 'down' : 'up')
|
|
480
|
-
}
|
|
481
|
-
|
|
482
447
|
function genShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, warpObj) {
|
|
483
448
|
const xfrmList = ['p:spPr', 'a:xfrm']
|
|
484
449
|
const slideXfrmNode = getTextByPathList(node, xfrmList)
|
|
@@ -488,17 +453,11 @@ function genShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, typ
|
|
|
488
453
|
const shapType = getTextByPathList(node, ['p:spPr', 'a:prstGeom', 'attrs', 'prst'])
|
|
489
454
|
const custShapType = getTextByPathList(node, ['p:spPr', 'a:custGeom'])
|
|
490
455
|
|
|
491
|
-
const { top, left } = getPosition(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode)
|
|
492
|
-
const { width, height } = getSize(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode)
|
|
456
|
+
const { top, left } = getPosition(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode, SLIDE_FACTOR)
|
|
457
|
+
const { width, height } = getSize(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode, SLIDE_FACTOR)
|
|
493
458
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (getTextByPathList(slideXfrmNode, ['attrs', 'flipV']) === '1') {
|
|
497
|
-
isFlipV = true
|
|
498
|
-
}
|
|
499
|
-
if (getTextByPathList(slideXfrmNode, ['attrs', 'flipH']) === '1') {
|
|
500
|
-
isFlipH = true
|
|
501
|
-
}
|
|
459
|
+
const isFlipV = getTextByPathList(slideXfrmNode, ['attrs', 'flipV']) === '1'
|
|
460
|
+
const isFlipH = getTextByPathList(slideXfrmNode, ['attrs', 'flipH']) === '1'
|
|
502
461
|
|
|
503
462
|
const rotate = angleToDegrees(getTextByPathList(slideXfrmNode, ['attrs', 'rot']))
|
|
504
463
|
|
|
@@ -511,273 +470,176 @@ function genShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, typ
|
|
|
511
470
|
else txtRotate = rotate
|
|
512
471
|
|
|
513
472
|
let content = ''
|
|
514
|
-
if (node['p:txBody']) content = genTextBody(node['p:txBody'], slideLayoutSpNode, slideMasterSpNode, type, warpObj)
|
|
473
|
+
if (node['p:txBody']) content = genTextBody(node['p:txBody'], slideLayoutSpNode, slideMasterSpNode, type, warpObj, FONTSIZE_FACTOR, SLIDE_FACTOR)
|
|
515
474
|
|
|
516
|
-
const { borderColor, borderWidth, borderType } = getBorder(node, type)
|
|
517
|
-
const fillColor = getShapeFill(node) || ''
|
|
475
|
+
const { borderColor, borderWidth, borderType, strokeDasharray } = getBorder(node, type, warpObj)
|
|
476
|
+
const fillColor = getShapeFill(node, undefined, warpObj) || ''
|
|
518
477
|
|
|
519
|
-
|
|
478
|
+
let shadow
|
|
479
|
+
const outerShdwNode = getTextByPathList(node, ['p:spPr', 'a:effectLst', 'a:outerShdw'])
|
|
480
|
+
if (outerShdwNode) shadow = getShadow(outerShdwNode, warpObj, SLIDE_FACTOR)
|
|
520
481
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const pathNodes = getTextByPathList(pathLstNode, ['a:path'])
|
|
524
|
-
const maxX = parseInt(pathNodes['attrs']['w'])
|
|
525
|
-
const maxY = parseInt(pathNodes['attrs']['h'])
|
|
526
|
-
const ext = getTextByPathList(slideXfrmNode, ['a:ext', 'attrs'])
|
|
527
|
-
const cx = parseInt(ext['cx']) * FACTOR
|
|
528
|
-
const cy = parseInt(ext['cy']) * FACTOR
|
|
529
|
-
const w = parseInt(ext['cx']) * FACTOR
|
|
530
|
-
const h = parseInt(ext['cy']) * FACTOR
|
|
531
|
-
const cX = (1 / maxX) * w
|
|
532
|
-
const cY = (1 / maxY) * h
|
|
533
|
-
let d = ''
|
|
534
|
-
|
|
535
|
-
let moveToNode = getTextByPathList(pathNodes, ['a:moveTo'])
|
|
536
|
-
|
|
537
|
-
const lnToNodes = pathNodes['a:lnTo']
|
|
538
|
-
let cubicBezToNodes = pathNodes['a:cubicBezTo']
|
|
539
|
-
const arcToNodes = pathNodes['a:arcTo']
|
|
540
|
-
let closeNode = getTextByPathList(pathNodes, ['a:close'])
|
|
541
|
-
if (!Array.isArray(moveToNode)) {
|
|
542
|
-
moveToNode = [moveToNode]
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
const multiSapeAry = []
|
|
546
|
-
if (moveToNode.length > 0) {
|
|
547
|
-
// a:moveTo
|
|
548
|
-
Object.keys(moveToNode).forEach(key => {
|
|
549
|
-
const moveToPtNode = moveToNode[key]['a:pt']
|
|
550
|
-
if (moveToPtNode) {
|
|
551
|
-
Object.keys(moveToPtNode).forEach(key2 => {
|
|
552
|
-
const moveToNoPt = moveToPtNode[key2]
|
|
553
|
-
const spX = moveToNoPt['attrs', 'x']
|
|
554
|
-
const spY = moveToNoPt['attrs', 'y']
|
|
555
|
-
|
|
556
|
-
multiSapeAry.push({
|
|
557
|
-
type: 'movto',
|
|
558
|
-
x: spX,
|
|
559
|
-
y: spY,
|
|
560
|
-
})
|
|
561
|
-
})
|
|
562
|
-
}
|
|
563
|
-
})
|
|
564
|
-
// a:lnTo
|
|
565
|
-
if (lnToNodes) {
|
|
566
|
-
Object.keys(lnToNodes).forEach(key => {
|
|
567
|
-
const lnToPtNode = lnToNodes[key]['a:pt']
|
|
568
|
-
if (lnToPtNode) {
|
|
569
|
-
Object.keys(lnToPtNode).forEach(key2 => {
|
|
570
|
-
const lnToNoPt = lnToPtNode[key2]
|
|
571
|
-
const ptX = lnToNoPt['attrs', 'x']
|
|
572
|
-
const ptY = lnToNoPt['attrs', 'y']
|
|
573
|
-
multiSapeAry.push({
|
|
574
|
-
type: 'lnto',
|
|
575
|
-
x: ptX,
|
|
576
|
-
y: ptY,
|
|
577
|
-
})
|
|
578
|
-
})
|
|
579
|
-
}
|
|
580
|
-
})
|
|
581
|
-
}
|
|
582
|
-
// a:cubicBezTo
|
|
583
|
-
if (cubicBezToNodes) {
|
|
584
|
-
|
|
585
|
-
const cubicBezToPtNodesAry = []
|
|
586
|
-
if (!Array.isArray(cubicBezToNodes)) {
|
|
587
|
-
cubicBezToNodes = [cubicBezToNodes]
|
|
588
|
-
}
|
|
589
|
-
Object.keys(cubicBezToNodes).forEach(key => {
|
|
590
|
-
cubicBezToPtNodesAry.push(cubicBezToNodes[key]['a:pt'])
|
|
591
|
-
})
|
|
592
|
-
|
|
593
|
-
cubicBezToPtNodesAry.forEach(key2 => {
|
|
594
|
-
const pts_ary = []
|
|
595
|
-
key2.forEach(pt => {
|
|
596
|
-
const pt_obj = {
|
|
597
|
-
x: pt['attrs']['x'],
|
|
598
|
-
y: pt['attrs']['y'],
|
|
599
|
-
}
|
|
600
|
-
pts_ary.push(pt_obj)
|
|
601
|
-
})
|
|
602
|
-
multiSapeAry.push({
|
|
603
|
-
type: 'cubicBezTo',
|
|
604
|
-
cubBzPt: pts_ary
|
|
605
|
-
})
|
|
606
|
-
})
|
|
607
|
-
}
|
|
608
|
-
// a:arcTo
|
|
609
|
-
if (arcToNodes) {
|
|
610
|
-
const arcToNodesAttrs = arcToNodes['attrs']
|
|
611
|
-
const hR = arcToNodesAttrs['hR']
|
|
612
|
-
const wR = arcToNodesAttrs['wR']
|
|
613
|
-
const stAng = arcToNodesAttrs['stAng']
|
|
614
|
-
const swAng = arcToNodesAttrs['swAng']
|
|
615
|
-
let shftX = 0
|
|
616
|
-
let shftY = 0
|
|
617
|
-
const arcToPtNode = getTextByPathList(arcToNodes, ['a:pt', 'attrs'])
|
|
618
|
-
if (arcToPtNode) {
|
|
619
|
-
shftX = arcToPtNode['x']
|
|
620
|
-
shftY = arcToPtNode['y']
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
multiSapeAry.push({
|
|
624
|
-
type: 'arcTo',
|
|
625
|
-
hR: hR,
|
|
626
|
-
wR: wR,
|
|
627
|
-
stAng: stAng,
|
|
628
|
-
swAng: swAng,
|
|
629
|
-
shftX: shftX,
|
|
630
|
-
shftY: shftY,
|
|
631
|
-
})
|
|
482
|
+
const vAlign = getVerticalAlign(node, slideLayoutSpNode, slideMasterSpNode, type)
|
|
483
|
+
const isVertical = getTextByPathList(node, ['p:txBody', 'a:bodyPr', 'attrs', 'vert']) === 'eaVert'
|
|
632
484
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
485
|
+
const data = {
|
|
486
|
+
left,
|
|
487
|
+
top,
|
|
488
|
+
width,
|
|
489
|
+
height,
|
|
490
|
+
borderColor,
|
|
491
|
+
borderWidth,
|
|
492
|
+
borderType,
|
|
493
|
+
borderStrokeDasharray: strokeDasharray,
|
|
494
|
+
fillColor,
|
|
495
|
+
content,
|
|
496
|
+
isFlipV,
|
|
497
|
+
isFlipH,
|
|
498
|
+
rotate,
|
|
499
|
+
vAlign,
|
|
500
|
+
id,
|
|
501
|
+
name,
|
|
502
|
+
idx,
|
|
503
|
+
}
|
|
643
504
|
|
|
644
|
-
|
|
645
|
-
while (k < multiSapeAry.length) {
|
|
505
|
+
if (shadow) data.shadow = shadow
|
|
646
506
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
const Ly = parseInt(multiSapeAry[k].y) * cY
|
|
655
|
-
d += ' L' + Lx + ',' + Ly
|
|
656
|
-
}
|
|
657
|
-
else if (multiSapeAry[k].type === 'cubicBezTo') {
|
|
658
|
-
const Cx1 = parseInt(multiSapeAry[k].cubBzPt[0].x) * cX
|
|
659
|
-
const Cy1 = parseInt(multiSapeAry[k].cubBzPt[0].y) * cY
|
|
660
|
-
const Cx2 = parseInt(multiSapeAry[k].cubBzPt[1].x) * cX
|
|
661
|
-
const Cy2 = parseInt(multiSapeAry[k].cubBzPt[1].y) * cY
|
|
662
|
-
const Cx3 = parseInt(multiSapeAry[k].cubBzPt[2].x) * cX
|
|
663
|
-
const Cy3 = parseInt(multiSapeAry[k].cubBzPt[2].y) * cY
|
|
664
|
-
d += ' C' + Cx1 + ',' + Cy1 + ' ' + Cx2 + ',' + Cy2 + ' ' + Cx3 + ',' + Cy3
|
|
665
|
-
}
|
|
666
|
-
else if (multiSapeAry[k].type === 'arcTo') {
|
|
667
|
-
const hR = parseInt(multiSapeAry[k].hR) * cX
|
|
668
|
-
const wR = parseInt(multiSapeAry[k].wR) * cY
|
|
669
|
-
const stAng = parseInt(multiSapeAry[k].stAng) / 60000
|
|
670
|
-
const swAng = parseInt(multiSapeAry[k].swAng) / 60000
|
|
671
|
-
const endAng = stAng + swAng
|
|
672
|
-
d += shapeArc(wR, hR, wR, hR, stAng, endAng, false)
|
|
673
|
-
}
|
|
674
|
-
else if (multiSapeAry[k].type === 'close') {
|
|
675
|
-
d += 'z'
|
|
676
|
-
}
|
|
677
|
-
k++
|
|
678
|
-
}
|
|
679
|
-
}
|
|
507
|
+
if (custShapType && type !== 'diagram') {
|
|
508
|
+
const ext = getTextByPathList(slideXfrmNode, ['a:ext', 'attrs'])
|
|
509
|
+
const cx = parseInt(ext['cx']) * SLIDE_FACTOR
|
|
510
|
+
const cy = parseInt(ext['cy']) * SLIDE_FACTOR
|
|
511
|
+
const w = parseInt(ext['cx']) * SLIDE_FACTOR
|
|
512
|
+
const h = parseInt(ext['cy']) * SLIDE_FACTOR
|
|
513
|
+
const d = getCustomShapePath(custShapType, w, h)
|
|
680
514
|
|
|
681
515
|
return {
|
|
516
|
+
...data,
|
|
682
517
|
type: 'shape',
|
|
683
|
-
left,
|
|
684
|
-
top,
|
|
685
|
-
width,
|
|
686
|
-
height,
|
|
687
518
|
cx,
|
|
688
519
|
cy,
|
|
689
|
-
borderColor,
|
|
690
|
-
borderWidth,
|
|
691
|
-
borderType,
|
|
692
|
-
fillColor,
|
|
693
|
-
content,
|
|
694
|
-
isFlipV,
|
|
695
|
-
isFlipH,
|
|
696
|
-
rotate,
|
|
697
520
|
shapType: 'custom',
|
|
698
|
-
vAlign,
|
|
699
521
|
path: d,
|
|
700
|
-
id,
|
|
701
|
-
name,
|
|
702
|
-
idx,
|
|
703
522
|
}
|
|
704
523
|
}
|
|
705
|
-
|
|
706
|
-
if (shapType) {
|
|
524
|
+
if (shapType && type !== 'text') {
|
|
707
525
|
const ext = getTextByPathList(slideXfrmNode, ['a:ext', 'attrs'])
|
|
708
|
-
const cx = parseInt(ext['cx']) *
|
|
709
|
-
const cy = parseInt(ext['cy']) *
|
|
526
|
+
const cx = parseInt(ext['cx']) * SLIDE_FACTOR
|
|
527
|
+
const cy = parseInt(ext['cy']) * SLIDE_FACTOR
|
|
710
528
|
|
|
711
529
|
return {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
top,
|
|
715
|
-
width,
|
|
716
|
-
height,
|
|
530
|
+
...data,
|
|
531
|
+
type: 'shape',
|
|
717
532
|
cx,
|
|
718
533
|
cy,
|
|
719
|
-
borderColor,
|
|
720
|
-
borderWidth,
|
|
721
|
-
borderType,
|
|
722
|
-
fillColor,
|
|
723
|
-
content,
|
|
724
|
-
isFlipV,
|
|
725
|
-
isFlipH,
|
|
726
|
-
rotate,
|
|
727
534
|
shapType,
|
|
728
|
-
vAlign,
|
|
729
|
-
id,
|
|
730
|
-
name,
|
|
731
|
-
idx,
|
|
732
535
|
}
|
|
733
536
|
}
|
|
734
|
-
|
|
735
537
|
return {
|
|
538
|
+
...data,
|
|
736
539
|
type: 'text',
|
|
737
|
-
|
|
738
|
-
top,
|
|
739
|
-
width,
|
|
740
|
-
height,
|
|
741
|
-
borderColor,
|
|
742
|
-
borderWidth,
|
|
743
|
-
borderType,
|
|
744
|
-
fillColor,
|
|
745
|
-
isFlipV,
|
|
746
|
-
isFlipH,
|
|
540
|
+
isVertical,
|
|
747
541
|
rotate: txtRotate,
|
|
748
|
-
content,
|
|
749
|
-
vAlign,
|
|
750
|
-
id,
|
|
751
|
-
name,
|
|
752
|
-
idx,
|
|
753
542
|
}
|
|
754
543
|
}
|
|
755
544
|
|
|
756
|
-
async function processPicNode(node, warpObj) {
|
|
545
|
+
async function processPicNode(node, warpObj, source) {
|
|
546
|
+
let resObj
|
|
547
|
+
if (source === 'slideMasterBg') resObj = warpObj['masterResObj']
|
|
548
|
+
else if (source === 'slideLayoutBg') resObj = warpObj['layoutResObj']
|
|
549
|
+
else resObj = warpObj['slideResObj']
|
|
550
|
+
|
|
757
551
|
const rid = node['p:blipFill']['a:blip']['attrs']['r:embed']
|
|
758
|
-
const imgName =
|
|
552
|
+
const imgName = resObj[rid]['target']
|
|
759
553
|
const imgFileExt = extractFileExtension(imgName).toLowerCase()
|
|
760
554
|
const zip = warpObj['zip']
|
|
761
555
|
const imgArrayBuffer = await zip.file(imgName).async('arraybuffer')
|
|
762
556
|
const xfrmNode = node['p:spPr']['a:xfrm']
|
|
763
557
|
|
|
764
558
|
const mimeType = getMimeType(imgFileExt)
|
|
765
|
-
const { top, left } = getPosition(xfrmNode, undefined, undefined)
|
|
766
|
-
const { width, height } = getSize(xfrmNode, undefined, undefined)
|
|
559
|
+
const { top, left } = getPosition(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
560
|
+
const { width, height } = getSize(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
767
561
|
const src = `data:${mimeType};base64,${base64ArrayBuffer(imgArrayBuffer)}`
|
|
768
562
|
|
|
769
563
|
let rotate = 0
|
|
770
564
|
const rotateNode = getTextByPathList(node, ['p:spPr', 'a:xfrm', 'attrs', 'rot'])
|
|
771
565
|
if (rotateNode) rotate = angleToDegrees(rotateNode)
|
|
772
566
|
|
|
567
|
+
const videoNode = getTextByPathList(node, ['p:nvPicPr', 'p:nvPr', 'a:videoFile'])
|
|
568
|
+
let videoRid, videoFile, videoFileExt, videoMimeType, uInt8ArrayVideo, videoBlob
|
|
569
|
+
let isVdeoLink = false
|
|
570
|
+
|
|
571
|
+
if (videoNode) {
|
|
572
|
+
videoRid = videoNode['attrs']['r:link']
|
|
573
|
+
videoFile = resObj[videoRid]['target']
|
|
574
|
+
if (isVideoLink(videoFile)) {
|
|
575
|
+
videoFile = escapeHtml(videoFile)
|
|
576
|
+
isVdeoLink = true
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
videoFileExt = extractFileExtension(videoFile).toLowerCase()
|
|
580
|
+
if (videoFileExt === 'mp4' || videoFileExt === 'webm' || videoFileExt === 'ogg') {
|
|
581
|
+
uInt8ArrayVideo = await zip.file(videoFile).async('arraybuffer')
|
|
582
|
+
videoMimeType = getMimeType(videoFileExt)
|
|
583
|
+
videoBlob = URL.createObjectURL(new Blob([uInt8ArrayVideo], {
|
|
584
|
+
type: videoMimeType
|
|
585
|
+
}))
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const audioNode = getTextByPathList(node, ['p:nvPicPr', 'p:nvPr', 'a:audioFile'])
|
|
591
|
+
let audioRid, audioFile, audioFileExt, uInt8ArrayAudio, audioBlob
|
|
592
|
+
if (audioNode) {
|
|
593
|
+
audioRid = audioNode['attrs']['r:link']
|
|
594
|
+
audioFile = resObj[audioRid]['target']
|
|
595
|
+
audioFileExt = extractFileExtension(audioFile).toLowerCase()
|
|
596
|
+
if (audioFileExt === 'mp3' || audioFileExt === 'wav' || audioFileExt === 'ogg') {
|
|
597
|
+
uInt8ArrayAudio = await zip.file(audioFile).async('arraybuffer')
|
|
598
|
+
audioBlob = URL.createObjectURL(new Blob([uInt8ArrayAudio]))
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (videoNode && !isVdeoLink) {
|
|
603
|
+
return {
|
|
604
|
+
type: 'video',
|
|
605
|
+
top,
|
|
606
|
+
left,
|
|
607
|
+
width,
|
|
608
|
+
height,
|
|
609
|
+
rotate,
|
|
610
|
+
blob: videoBlob,
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (videoNode && isVdeoLink) {
|
|
614
|
+
return {
|
|
615
|
+
type: 'video',
|
|
616
|
+
top,
|
|
617
|
+
left,
|
|
618
|
+
width,
|
|
619
|
+
height,
|
|
620
|
+
rotate,
|
|
621
|
+
src: videoFile,
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (audioNode) {
|
|
625
|
+
return {
|
|
626
|
+
type: 'audio',
|
|
627
|
+
top,
|
|
628
|
+
left,
|
|
629
|
+
width,
|
|
630
|
+
height,
|
|
631
|
+
rotate,
|
|
632
|
+
blob: audioBlob,
|
|
633
|
+
}
|
|
634
|
+
}
|
|
773
635
|
return {
|
|
774
636
|
type: 'image',
|
|
775
637
|
top,
|
|
776
638
|
left,
|
|
777
639
|
width,
|
|
778
640
|
height,
|
|
779
|
-
src,
|
|
780
641
|
rotate,
|
|
642
|
+
src,
|
|
781
643
|
}
|
|
782
644
|
}
|
|
783
645
|
|
|
@@ -805,121 +667,11 @@ async function processGraphicFrameNode(node, warpObj) {
|
|
|
805
667
|
return result
|
|
806
668
|
}
|
|
807
669
|
|
|
808
|
-
function genTextBody(textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj) {
|
|
809
|
-
if (!textBodyNode) return ''
|
|
810
|
-
|
|
811
|
-
let text = ''
|
|
812
|
-
const slideMasterTextStyles = warpObj['slideMasterTextStyles']
|
|
813
|
-
|
|
814
|
-
const pNode = textBodyNode['a:p']
|
|
815
|
-
const pNodes = pNode.constructor === Array ? pNode : [pNode]
|
|
816
|
-
|
|
817
|
-
let isList = ''
|
|
818
|
-
|
|
819
|
-
for (const pNode of pNodes) {
|
|
820
|
-
let rNode = pNode['a:r']
|
|
821
|
-
let fldNode = pNode['a:fld']
|
|
822
|
-
let brNode = pNode['a:br']
|
|
823
|
-
if (rNode) {
|
|
824
|
-
rNode = (rNode.constructor === Array) ? rNode : [rNode]
|
|
825
|
-
|
|
826
|
-
if (fldNode) {
|
|
827
|
-
fldNode = (fldNode.constructor === Array) ? fldNode : [fldNode]
|
|
828
|
-
rNode = rNode.concat(fldNode)
|
|
829
|
-
}
|
|
830
|
-
if (brNode) {
|
|
831
|
-
brNode = (brNode.constructor === Array) ? brNode : [brNode]
|
|
832
|
-
brNode.forEach(item => item.type = 'br')
|
|
833
|
-
|
|
834
|
-
if (brNode.length > 1) brNode.shift()
|
|
835
|
-
rNode = rNode.concat(brNode)
|
|
836
|
-
rNode.sort((a, b) => {
|
|
837
|
-
if (!a.attrs || !b.attrs) return true
|
|
838
|
-
return a.attrs.order - b.attrs.order
|
|
839
|
-
})
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
const align = getHorizontalAlign(pNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles)
|
|
844
|
-
|
|
845
|
-
const listType = getListType(pNode)
|
|
846
|
-
if (listType) {
|
|
847
|
-
if (!isList) {
|
|
848
|
-
text += `<${listType}>`
|
|
849
|
-
isList = listType
|
|
850
|
-
}
|
|
851
|
-
else if (isList && isList !== listType) {
|
|
852
|
-
text += `</${isList}>`
|
|
853
|
-
text += `<${listType}>`
|
|
854
|
-
isList = listType
|
|
855
|
-
}
|
|
856
|
-
text += `<li style="text-align: ${align};">`
|
|
857
|
-
}
|
|
858
|
-
else {
|
|
859
|
-
if (isList) {
|
|
860
|
-
text += `</${isList}>`
|
|
861
|
-
isList = ''
|
|
862
|
-
}
|
|
863
|
-
text += `<p style="text-align: ${align};">`
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
if (!rNode) text += genSpanElement(pNode, slideLayoutSpNode, type, warpObj)
|
|
867
|
-
else {
|
|
868
|
-
for (const rNodeItem of rNode) {
|
|
869
|
-
text += genSpanElement(rNodeItem, slideLayoutSpNode, type, warpObj)
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
if (listType) text += '</li>'
|
|
874
|
-
else text += '</p>'
|
|
875
|
-
}
|
|
876
|
-
return text
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
function getListType(node) {
|
|
880
|
-
const pPrNode = node['a:pPr']
|
|
881
|
-
if (!pPrNode) return ''
|
|
882
|
-
|
|
883
|
-
if (pPrNode['a:buChar']) return 'ul'
|
|
884
|
-
if (pPrNode['a:buAutoNum']) return 'ol'
|
|
885
|
-
|
|
886
|
-
return ''
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
function genSpanElement(node, slideLayoutSpNode, type, warpObj) {
|
|
890
|
-
const slideMasterTextStyles = warpObj['slideMasterTextStyles']
|
|
891
|
-
|
|
892
|
-
let text = node['a:t']
|
|
893
|
-
if (typeof text !== 'string') text = getTextByPathList(node, ['a:fld', 'a:t'])
|
|
894
|
-
if (typeof text !== 'string') text = ' '
|
|
895
|
-
|
|
896
|
-
let styleText = ''
|
|
897
|
-
const fontColor = getFontColor(node)
|
|
898
|
-
const fontSize = getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles)
|
|
899
|
-
const fontType = getFontType(node, type)
|
|
900
|
-
const fontBold = getFontBold(node)
|
|
901
|
-
const fontItalic = getFontItalic(node)
|
|
902
|
-
const fontDecoration = getFontDecoration(node)
|
|
903
|
-
if (fontColor) styleText += `color: ${fontColor};`
|
|
904
|
-
if (fontSize) styleText += `font-size: ${fontSize};`
|
|
905
|
-
if (fontType) styleText += `font-family: ${fontType};`
|
|
906
|
-
if (fontBold) styleText += `font-weight: ${fontBold};`
|
|
907
|
-
if (fontItalic) styleText += `font-style: ${fontItalic};`
|
|
908
|
-
if (fontDecoration) styleText += `text-decoration: ${fontDecoration};`
|
|
909
|
-
|
|
910
|
-
const linkID = getTextByPathList(node, ['a:rPr', 'a:hlinkClick', 'attrs', 'r:id'])
|
|
911
|
-
if (linkID) {
|
|
912
|
-
const linkURL = warpObj['slideResObj'][linkID]['target']
|
|
913
|
-
return `<span style="${styleText}"><a href="${linkURL}" target="_blank">${text.replace(/\s/i, ' ')}</a></span>`
|
|
914
|
-
}
|
|
915
|
-
return `<span style="${styleText}">${text.replace(/\s/i, ' ')}</span>`
|
|
916
|
-
}
|
|
917
|
-
|
|
918
670
|
function genTable(node, warpObj) {
|
|
919
671
|
const tableNode = getTextByPathList(node, ['a:graphic', 'a:graphicData', 'a:tbl'])
|
|
920
672
|
const xfrmNode = getTextByPathList(node, ['p:xfrm'])
|
|
921
|
-
const { top, left } = getPosition(xfrmNode, undefined, undefined)
|
|
922
|
-
const { width, height } = getSize(xfrmNode, undefined, undefined)
|
|
673
|
+
const { top, left } = getPosition(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
674
|
+
const { width, height } = getSize(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
923
675
|
|
|
924
676
|
const trNodes = tableNode['a:tr']
|
|
925
677
|
|
|
@@ -931,7 +683,7 @@ function genTable(node, warpObj) {
|
|
|
931
683
|
|
|
932
684
|
if (tcNodes.constructor === Array) {
|
|
933
685
|
for (const tcNode of tcNodes) {
|
|
934
|
-
const text = genTextBody(tcNode['a:txBody'], undefined, undefined, undefined, warpObj)
|
|
686
|
+
const text = genTextBody(tcNode['a:txBody'], undefined, undefined, undefined, warpObj, FONTSIZE_FACTOR, SLIDE_FACTOR)
|
|
935
687
|
const rowSpan = getTextByPathList(tcNode, ['attrs', 'rowSpan'])
|
|
936
688
|
const colSpan = getTextByPathList(tcNode, ['attrs', 'gridSpan'])
|
|
937
689
|
const vMerge = getTextByPathList(tcNode, ['attrs', 'vMerge'])
|
|
@@ -941,10 +693,9 @@ function genTable(node, warpObj) {
|
|
|
941
693
|
}
|
|
942
694
|
}
|
|
943
695
|
else {
|
|
944
|
-
const text = genTextBody(tcNodes['a:txBody'], undefined, undefined, undefined, warpObj)
|
|
696
|
+
const text = genTextBody(tcNodes['a:txBody'], undefined, undefined, undefined, warpObj, FONTSIZE_FACTOR, SLIDE_FACTOR)
|
|
945
697
|
tr.push({ text })
|
|
946
698
|
}
|
|
947
|
-
|
|
948
699
|
data.push(tr)
|
|
949
700
|
}
|
|
950
701
|
}
|
|
@@ -954,12 +705,12 @@ function genTable(node, warpObj) {
|
|
|
954
705
|
|
|
955
706
|
if (tcNodes.constructor === Array) {
|
|
956
707
|
for (const tcNode of tcNodes) {
|
|
957
|
-
const text = genTextBody(tcNode['a:txBody'], undefined, undefined, undefined, warpObj)
|
|
708
|
+
const text = genTextBody(tcNode['a:txBody'], undefined, undefined, undefined, warpObj, FONTSIZE_FACTOR, SLIDE_FACTOR)
|
|
958
709
|
tr.push({ text })
|
|
959
710
|
}
|
|
960
711
|
}
|
|
961
712
|
else {
|
|
962
|
-
const text = genTextBody(tcNodes['a:txBody'], undefined, undefined, undefined, warpObj)
|
|
713
|
+
const text = genTextBody(tcNodes['a:txBody'], undefined, undefined, undefined, warpObj, FONTSIZE_FACTOR, SLIDE_FACTOR)
|
|
963
714
|
tr.push({ text })
|
|
964
715
|
}
|
|
965
716
|
data.push(tr)
|
|
@@ -977,63 +728,19 @@ function genTable(node, warpObj) {
|
|
|
977
728
|
|
|
978
729
|
async function genChart(node, warpObj) {
|
|
979
730
|
const xfrmNode = getTextByPathList(node, ['p:xfrm'])
|
|
980
|
-
const { top, left } = getPosition(xfrmNode, undefined, undefined)
|
|
981
|
-
const { width, height } = getSize(xfrmNode, undefined, undefined)
|
|
731
|
+
const { top, left } = getPosition(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
732
|
+
const { width, height } = getSize(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
982
733
|
|
|
983
734
|
const rid = node['a:graphic']['a:graphicData']['c:chart']['attrs']['r:id']
|
|
984
735
|
const refName = warpObj['slideResObj'][rid]['target']
|
|
985
736
|
const content = await readXmlFile(warpObj['zip'], refName)
|
|
986
737
|
const plotArea = getTextByPathList(content, ['c:chartSpace', 'c:chart', 'c:plotArea'])
|
|
987
738
|
|
|
988
|
-
|
|
989
|
-
for (const key in plotArea) {
|
|
990
|
-
switch (key) {
|
|
991
|
-
case 'c:lineChart':
|
|
992
|
-
chart = {
|
|
993
|
-
type: 'lineChart',
|
|
994
|
-
data: extractChartData(plotArea[key]['c:ser']),
|
|
995
|
-
}
|
|
996
|
-
break
|
|
997
|
-
case 'c:barChart':
|
|
998
|
-
chart = {
|
|
999
|
-
type: getTextByPathList(plotArea[key], ['c:grouping', 'attrs', 'val']) === 'stacked' ? 'stackedBarChart' : 'barChart',
|
|
1000
|
-
data: extractChartData(plotArea[key]['c:ser']),
|
|
1001
|
-
}
|
|
1002
|
-
break
|
|
1003
|
-
case 'c:pieChart':
|
|
1004
|
-
chart = {
|
|
1005
|
-
type: 'pieChart',
|
|
1006
|
-
data: extractChartData(plotArea[key]['c:ser']),
|
|
1007
|
-
}
|
|
1008
|
-
break
|
|
1009
|
-
case 'c:pie3DChart':
|
|
1010
|
-
chart = {
|
|
1011
|
-
type: 'pie3DChart',
|
|
1012
|
-
data: extractChartData(plotArea[key]['c:ser']),
|
|
1013
|
-
}
|
|
1014
|
-
break
|
|
1015
|
-
case 'c:areaChart':
|
|
1016
|
-
chart = {
|
|
1017
|
-
type: getTextByPathList(plotArea[key], ['c:grouping', 'attrs', 'val']) === 'percentStacked' ? 'stackedAreaChart' : 'areaChart',
|
|
1018
|
-
data: extractChartData(plotArea[key]['c:ser']),
|
|
1019
|
-
}
|
|
1020
|
-
break
|
|
1021
|
-
case 'c:scatterChart':
|
|
1022
|
-
chart = {
|
|
1023
|
-
type: 'scatterChart',
|
|
1024
|
-
data: extractChartData(plotArea[key]['c:ser']),
|
|
1025
|
-
}
|
|
1026
|
-
break
|
|
1027
|
-
case 'c:catAx':
|
|
1028
|
-
break
|
|
1029
|
-
case 'c:valAx':
|
|
1030
|
-
break
|
|
1031
|
-
default:
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
739
|
+
const chart = getChartInfo(plotArea)
|
|
1034
740
|
|
|
1035
741
|
if (!chart) return {}
|
|
1036
|
-
|
|
742
|
+
|
|
743
|
+
const data = {
|
|
1037
744
|
type: 'chart',
|
|
1038
745
|
top,
|
|
1039
746
|
left,
|
|
@@ -1042,12 +749,28 @@ async function genChart(node, warpObj) {
|
|
|
1042
749
|
data: chart.data,
|
|
1043
750
|
chartType: chart.type,
|
|
1044
751
|
}
|
|
752
|
+
if (chart.marker !== undefined) data.marker = chart.marker
|
|
753
|
+
if (chart.barDir !== undefined) data.barDir = chart.barDir
|
|
754
|
+
if (chart.holeSize !== undefined) data.holeSize = chart.holeSize
|
|
755
|
+
if (chart.grouping !== undefined) data.grouping = chart.grouping
|
|
756
|
+
if (chart.style !== undefined) data.style = chart.style
|
|
757
|
+
|
|
758
|
+
return data
|
|
1045
759
|
}
|
|
1046
760
|
|
|
1047
|
-
function genDiagram(node) {
|
|
761
|
+
function genDiagram(node, warpObj) {
|
|
1048
762
|
const xfrmNode = getTextByPathList(node, ['p:xfrm'])
|
|
1049
|
-
const { left, top } = getPosition(xfrmNode, undefined, undefined)
|
|
1050
|
-
const { width, height } = getSize(xfrmNode, undefined, undefined)
|
|
763
|
+
const { left, top } = getPosition(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
764
|
+
const { width, height } = getSize(xfrmNode, undefined, undefined, SLIDE_FACTOR)
|
|
765
|
+
|
|
766
|
+
const dgmDrwSpArray = getTextByPathList(warpObj['digramFileContent'], ['p:drawing', 'p:spTree', 'p:sp'])
|
|
767
|
+
const elements = []
|
|
768
|
+
if (dgmDrwSpArray) {
|
|
769
|
+
for (const item of dgmDrwSpArray) {
|
|
770
|
+
const el = processSpNode(item, warpObj, 'diagramBg')
|
|
771
|
+
if (el) elements.push(el)
|
|
772
|
+
}
|
|
773
|
+
}
|
|
1051
774
|
|
|
1052
775
|
return {
|
|
1053
776
|
type: 'diagram',
|
|
@@ -1055,551 +778,6 @@ function genDiagram(node) {
|
|
|
1055
778
|
top,
|
|
1056
779
|
width,
|
|
1057
780
|
height,
|
|
781
|
+
elements,
|
|
1058
782
|
}
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
function getPosition(slideSpNode, slideLayoutSpNode, slideMasterSpNode) {
|
|
1062
|
-
let off
|
|
1063
|
-
|
|
1064
|
-
if (slideSpNode) off = slideSpNode['a:off']['attrs']
|
|
1065
|
-
else if (slideLayoutSpNode) off = slideLayoutSpNode['a:off']['attrs']
|
|
1066
|
-
else if (slideMasterSpNode) off = slideMasterSpNode['a:off']['attrs']
|
|
1067
|
-
|
|
1068
|
-
if (!off) return { top: 0, left: 0 }
|
|
1069
|
-
|
|
1070
|
-
return {
|
|
1071
|
-
top: parseInt(off['y']) * FACTOR,
|
|
1072
|
-
left: parseInt(off['x']) * FACTOR,
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
function getSize(slideSpNode, slideLayoutSpNode, slideMasterSpNode) {
|
|
1077
|
-
let ext
|
|
1078
|
-
|
|
1079
|
-
if (slideSpNode) ext = slideSpNode['a:ext']['attrs']
|
|
1080
|
-
else if (slideLayoutSpNode) ext = slideLayoutSpNode['a:ext']['attrs']
|
|
1081
|
-
else if (slideMasterSpNode) ext = slideMasterSpNode['a:ext']['attrs']
|
|
1082
|
-
|
|
1083
|
-
if (!ext) return { width: 0, height: 0 }
|
|
1084
|
-
|
|
1085
|
-
return {
|
|
1086
|
-
width: parseInt(ext['cx']) * FACTOR,
|
|
1087
|
-
height: parseInt(ext['cy']) * FACTOR,
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
function getHorizontalAlign(node, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles) {
|
|
1092
|
-
let algn = getTextByPathList(node, ['a:pPr', 'attrs', 'algn'])
|
|
1093
|
-
|
|
1094
|
-
if (!algn) algn = getTextByPathList(slideLayoutSpNode, ['p:txBody', 'a:p', 'a:pPr', 'attrs', 'algn'])
|
|
1095
|
-
if (!algn) algn = getTextByPathList(slideMasterSpNode, ['p:txBody', 'a:p', 'a:pPr', 'attrs', 'algn'])
|
|
1096
|
-
if (!algn) {
|
|
1097
|
-
switch (type) {
|
|
1098
|
-
case 'title':
|
|
1099
|
-
case 'subTitle':
|
|
1100
|
-
case 'ctrTitle':
|
|
1101
|
-
algn = getTextByPathList(slideMasterTextStyles, ['p:titleStyle', 'a:lvl1pPr', 'attrs', 'algn'])
|
|
1102
|
-
break
|
|
1103
|
-
default:
|
|
1104
|
-
algn = getTextByPathList(slideMasterTextStyles, ['p:otherStyle', 'a:lvl1pPr', 'attrs', 'algn'])
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
if (!algn) {
|
|
1108
|
-
if (type === 'title' || type === 'subTitle' || type === 'ctrTitle') return 'center'
|
|
1109
|
-
else if (type === 'sldNum') return 'right'
|
|
1110
|
-
}
|
|
1111
|
-
return algn === 'ctr' ? 'center' : algn === 'r' ? 'right' : 'left'
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
function getFontType(node, type) {
|
|
1115
|
-
let typeface = getTextByPathList(node, ['a:rPr', 'a:latin', 'attrs', 'typeface'])
|
|
1116
|
-
|
|
1117
|
-
if (!typeface) {
|
|
1118
|
-
const fontSchemeNode = getTextByPathList(themeContent, ['a:theme', 'a:themeElements', 'a:fontScheme'])
|
|
1119
|
-
|
|
1120
|
-
if (type === 'title' || type === 'subTitle' || type === 'ctrTitle') {
|
|
1121
|
-
typeface = getTextByPathList(fontSchemeNode, ['a:majorFont', 'a:latin', 'attrs', 'typeface'])
|
|
1122
|
-
}
|
|
1123
|
-
else if (type === 'body') {
|
|
1124
|
-
typeface = getTextByPathList(fontSchemeNode, ['a:minorFont', 'a:latin', 'attrs', 'typeface'])
|
|
1125
|
-
}
|
|
1126
|
-
else {
|
|
1127
|
-
typeface = getTextByPathList(fontSchemeNode, ['a:minorFont', 'a:latin', 'attrs', 'typeface'])
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
return typeface || ''
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
function getFontColor(node) {
|
|
1135
|
-
const color = getTextByPathList(node, ['a:rPr', 'a:solidFill', 'a:srgbClr', 'attrs', 'val'])
|
|
1136
|
-
return color ? `#${color}` : ''
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
function getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles) {
|
|
1140
|
-
let fontSize
|
|
1141
|
-
|
|
1142
|
-
if (node['a:rPr']) fontSize = parseInt(node['a:rPr']['attrs']['sz']) / 100
|
|
1143
|
-
|
|
1144
|
-
if ((isNaN(fontSize) || !fontSize)) {
|
|
1145
|
-
const sz = getTextByPathList(slideLayoutSpNode, ['p:txBody', 'a:lstStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz'])
|
|
1146
|
-
fontSize = parseInt(sz) / 100
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
if (isNaN(fontSize) || !fontSize) {
|
|
1150
|
-
let sz
|
|
1151
|
-
if (type === 'title' || type === 'subTitle' || type === 'ctrTitle') {
|
|
1152
|
-
sz = getTextByPathList(slideMasterTextStyles, ['p:titleStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz'])
|
|
1153
|
-
}
|
|
1154
|
-
else if (type === 'body') {
|
|
1155
|
-
sz = getTextByPathList(slideMasterTextStyles, ['p:bodyStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz'])
|
|
1156
|
-
}
|
|
1157
|
-
else if (type === 'dt' || type === 'sldNum') {
|
|
1158
|
-
sz = '1200'
|
|
1159
|
-
}
|
|
1160
|
-
else if (!type) {
|
|
1161
|
-
sz = getTextByPathList(slideMasterTextStyles, ['p:otherStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz'])
|
|
1162
|
-
}
|
|
1163
|
-
if (sz) fontSize = parseInt(sz) / 100
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
const baseline = getTextByPathList(node, ['a:rPr', 'attrs', 'baseline'])
|
|
1167
|
-
if (baseline && !isNaN(fontSize)) fontSize -= 10
|
|
1168
|
-
|
|
1169
|
-
return (isNaN(fontSize) || !fontSize) ? '18.75px' : (fontSize / 0.75 * (75 / 96) + 'px')
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
function getFontBold(node) {
|
|
1173
|
-
return (node['a:rPr'] && node['a:rPr']['attrs']['b'] === '1') ? 'bold' : ''
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
function getFontItalic(node) {
|
|
1177
|
-
return (node['a:rPr'] && node['a:rPr']['attrs']['i'] === '1') ? 'italic' : ''
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
function getFontDecoration(node) {
|
|
1181
|
-
return (node['a:rPr'] && node['a:rPr']['attrs']['u'] === 'sng') ? 'underline' : ''
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
function getBorder(node, elType) {
|
|
1185
|
-
const lineNode = node['p:spPr']['a:ln']
|
|
1186
|
-
|
|
1187
|
-
let borderWidth = parseInt(getTextByPathList(lineNode, ['attrs', 'w'])) / 12700
|
|
1188
|
-
if (isNaN(borderWidth)) {
|
|
1189
|
-
if (lineNode) borderWidth = 0
|
|
1190
|
-
else if (elType === 'text') borderWidth = 0
|
|
1191
|
-
else borderWidth = 1
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
let borderColor = getTextByPathList(lineNode, ['a:solidFill', 'a:srgbClr', 'attrs', 'val'])
|
|
1195
|
-
if (!borderColor) {
|
|
1196
|
-
const schemeClrNode = getTextByPathList(lineNode, ['a:solidFill', 'a:schemeClr'])
|
|
1197
|
-
const schemeClr = 'a:' + getTextByPathList(schemeClrNode, ['attrs', 'val'])
|
|
1198
|
-
borderColor = getSchemeColorFromTheme(schemeClr)
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
if (!borderColor) {
|
|
1202
|
-
const schemeClrNode = getTextByPathList(node, ['p:style', 'a:lnRef', 'a:schemeClr'])
|
|
1203
|
-
const schemeClr = 'a:' + getTextByPathList(schemeClrNode, ['attrs', 'val'])
|
|
1204
|
-
borderColor = getSchemeColorFromTheme(schemeClr)
|
|
1205
|
-
|
|
1206
|
-
if (borderColor) {
|
|
1207
|
-
let shade = getTextByPathList(schemeClrNode, ['a:shade', 'attrs', 'val'])
|
|
1208
|
-
|
|
1209
|
-
if (shade) {
|
|
1210
|
-
shade = parseInt(shade) / 100000
|
|
1211
|
-
|
|
1212
|
-
const color = tinycolor('#' + borderColor).toHsl()
|
|
1213
|
-
borderColor = tinycolor({ h: color.h, s: color.s, l: color.l * shade, a: color.a }).toHex()
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
if (!borderColor) borderColor = '#000'
|
|
1219
|
-
else borderColor = `#${borderColor}`
|
|
1220
|
-
|
|
1221
|
-
const type = getTextByPathList(lineNode, ['a:prstDash', 'attrs', 'val'])
|
|
1222
|
-
let borderType = 'solid'
|
|
1223
|
-
let strokeDasharray = '0'
|
|
1224
|
-
switch (type) {
|
|
1225
|
-
case 'solid':
|
|
1226
|
-
borderType = 'solid'
|
|
1227
|
-
strokeDasharray = '0'
|
|
1228
|
-
break
|
|
1229
|
-
case 'dash':
|
|
1230
|
-
borderType = 'dashed'
|
|
1231
|
-
strokeDasharray = '5'
|
|
1232
|
-
break
|
|
1233
|
-
case 'dashDot':
|
|
1234
|
-
borderType = 'dashed'
|
|
1235
|
-
strokeDasharray = '5, 5, 1, 5'
|
|
1236
|
-
break
|
|
1237
|
-
case 'dot':
|
|
1238
|
-
borderType = 'dotted'
|
|
1239
|
-
strokeDasharray = '1, 5'
|
|
1240
|
-
break
|
|
1241
|
-
case 'lgDash':
|
|
1242
|
-
borderType = 'dashed'
|
|
1243
|
-
strokeDasharray = '10, 5'
|
|
1244
|
-
break
|
|
1245
|
-
case 'lgDashDotDot':
|
|
1246
|
-
borderType = 'dashed'
|
|
1247
|
-
strokeDasharray = '10, 5, 1, 5, 1, 5'
|
|
1248
|
-
break
|
|
1249
|
-
case 'sysDash':
|
|
1250
|
-
borderType = 'dashed'
|
|
1251
|
-
strokeDasharray = '5, 2'
|
|
1252
|
-
break
|
|
1253
|
-
case 'sysDashDot':
|
|
1254
|
-
borderType = 'dashed'
|
|
1255
|
-
strokeDasharray = '5, 2, 1, 5'
|
|
1256
|
-
break
|
|
1257
|
-
case 'sysDashDotDot':
|
|
1258
|
-
borderType = 'dashed'
|
|
1259
|
-
strokeDasharray = '5, 2, 1, 5, 1, 5'
|
|
1260
|
-
break
|
|
1261
|
-
case 'sysDot':
|
|
1262
|
-
borderType = 'dotted'
|
|
1263
|
-
strokeDasharray = '2, 5'
|
|
1264
|
-
break
|
|
1265
|
-
default:
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
return {
|
|
1269
|
-
borderColor,
|
|
1270
|
-
borderWidth,
|
|
1271
|
-
borderType,
|
|
1272
|
-
strokeDasharray,
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
function getFillType(node) {
|
|
1277
|
-
let fillType = ''
|
|
1278
|
-
if (node['a:noFill']) fillType = 'NO_FILL'
|
|
1279
|
-
if (node['a:solidFill']) fillType = 'SOLID_FILL'
|
|
1280
|
-
if (node['a:gradFill']) fillType = 'GRADIENT_FILL'
|
|
1281
|
-
if (node['a:pattFill']) fillType = 'PATTERN_FILL'
|
|
1282
|
-
if (node['a:blipFill']) fillType = 'PIC_FILL'
|
|
1283
|
-
if (node['a:grpFill']) fillType = 'GROUP_FILL'
|
|
1284
|
-
|
|
1285
|
-
return fillType
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
async function getPicFill(type, node, warpObj) {
|
|
1289
|
-
let img
|
|
1290
|
-
const rId = node['a:blip']['attrs']['r:embed']
|
|
1291
|
-
let imgPath
|
|
1292
|
-
if (type === 'slideBg' || type === 'slide') {
|
|
1293
|
-
imgPath = getTextByPathList(warpObj, ['slideResObj', rId, 'target'])
|
|
1294
|
-
}
|
|
1295
|
-
else if (type === 'slideLayoutBg') {
|
|
1296
|
-
imgPath = getTextByPathList(warpObj, ['layoutResObj', rId, 'target'])
|
|
1297
|
-
}
|
|
1298
|
-
else if (type === 'slideMasterBg') {
|
|
1299
|
-
imgPath = getTextByPathList(warpObj, ['masterResObj', rId, 'target'])
|
|
1300
|
-
}
|
|
1301
|
-
else if (type === 'themeBg') {
|
|
1302
|
-
imgPath = getTextByPathList(warpObj, ['themeResObj', rId, 'target'])
|
|
1303
|
-
}
|
|
1304
|
-
if (!imgPath) return imgPath
|
|
1305
|
-
|
|
1306
|
-
img = getTextByPathList(warpObj, ['loaded-images', imgPath])
|
|
1307
|
-
if (!img) {
|
|
1308
|
-
imgPath = escapeHtml(imgPath)
|
|
1309
|
-
|
|
1310
|
-
const imgExt = imgPath.split('.').pop()
|
|
1311
|
-
if (imgExt === 'xml') return undefined
|
|
1312
|
-
|
|
1313
|
-
const imgArrayBuffer = await warpObj['zip'].file(imgPath).async('arraybuffer')
|
|
1314
|
-
const imgMimeType = getMimeType(imgExt)
|
|
1315
|
-
img = `data:${imgMimeType};base64,${base64ArrayBuffer(imgArrayBuffer)}`
|
|
1316
|
-
}
|
|
1317
|
-
return img
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
async function getBgPicFill(bgPr, sorce, warpObj) {
|
|
1321
|
-
const picBase64 = await getPicFill(sorce, bgPr['a:blipFill'], warpObj)
|
|
1322
|
-
const aBlipNode = bgPr['a:blipFill']['a:blip']
|
|
1323
|
-
|
|
1324
|
-
const aphaModFixNode = getTextByPathList(aBlipNode, ['a:alphaModFix', 'attrs'])
|
|
1325
|
-
let opacity = 1
|
|
1326
|
-
if (aphaModFixNode && aphaModFixNode['amt'] && aphaModFixNode['amt'] !== '') {
|
|
1327
|
-
opacity = parseInt(aphaModFixNode['amt']) / 100000
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
return {
|
|
1331
|
-
picBase64,
|
|
1332
|
-
opacity,
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
function getBgGradientFill(bgPr, phClr, slideMasterContent, warpObj) {
|
|
1337
|
-
if (bgPr) {
|
|
1338
|
-
const grdFill = bgPr['a:gradFill']
|
|
1339
|
-
const gsLst = grdFill['a:gsLst']['a:gs']
|
|
1340
|
-
const color_ary = []
|
|
1341
|
-
const pos_ary = []
|
|
1342
|
-
|
|
1343
|
-
for (let i = 0; i < gsLst.length; i++) {
|
|
1344
|
-
const lo_color = getSolidFill(gsLst[i], slideMasterContent['p:sldMaster']['p:clrMap']['attrs'], phClr, warpObj)
|
|
1345
|
-
const pos = getTextByPathList(gsLst[i], ['attrs', 'pos'])
|
|
1346
|
-
|
|
1347
|
-
if (pos) pos_ary[i] = pos / 1000 + '%'
|
|
1348
|
-
else pos_ary[i] = ''
|
|
1349
|
-
color_ary[i] = `#${lo_color}`
|
|
1350
|
-
}
|
|
1351
|
-
const lin = grdFill['a:lin']
|
|
1352
|
-
let rot = 90
|
|
1353
|
-
if (lin) {
|
|
1354
|
-
rot = angleToDegrees(lin['attrs']['ang'])
|
|
1355
|
-
rot = rot + 90
|
|
1356
|
-
}
|
|
1357
|
-
return {
|
|
1358
|
-
rot,
|
|
1359
|
-
colors: color_ary,
|
|
1360
|
-
pos: pos_ary,
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
else if (phClr) return `#${phClr}`
|
|
1364
|
-
return null
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
async function getSlideBackgroundFill(warpObj) {
|
|
1368
|
-
const slideContent = warpObj['slideContent']
|
|
1369
|
-
const slideLayoutContent = warpObj['slideLayoutContent']
|
|
1370
|
-
const slideMasterContent = warpObj['slideMasterContent']
|
|
1371
|
-
|
|
1372
|
-
let bgPr = getTextByPathList(slideContent, ['p:sld', 'p:cSld', 'p:bg', 'p:bgPr'])
|
|
1373
|
-
|
|
1374
|
-
let background = '#fff'
|
|
1375
|
-
let backgroundType = 'color'
|
|
1376
|
-
|
|
1377
|
-
if (bgPr) {
|
|
1378
|
-
const bgFillTyp = getFillType(bgPr)
|
|
1379
|
-
|
|
1380
|
-
if (bgFillTyp === 'SOLID_FILL') {
|
|
1381
|
-
const sldFill = bgPr['a:solidFill']
|
|
1382
|
-
let clrMapOvr
|
|
1383
|
-
const sldClrMapOvr = getTextByPathList(slideContent, ['p:sld', 'p:clrMapOvr', 'a:overrideClrMapping', 'attrs'])
|
|
1384
|
-
if (sldClrMapOvr) clrMapOvr = sldClrMapOvr
|
|
1385
|
-
else {
|
|
1386
|
-
const sldClrMapOvr = getTextByPathList(slideLayoutContent, ['p:sldLayout', 'p:clrMapOvr', 'a:overrideClrMapping', 'attrs'])
|
|
1387
|
-
if (sldClrMapOvr) clrMapOvr = sldClrMapOvr
|
|
1388
|
-
else clrMapOvr = getTextByPathList(slideMasterContent, ['p:sldMaster', 'p:clrMap', 'attrs'])
|
|
1389
|
-
}
|
|
1390
|
-
const sldBgClr = getSolidFill(sldFill, clrMapOvr, undefined, warpObj)
|
|
1391
|
-
background = `#${sldBgClr}`
|
|
1392
|
-
}
|
|
1393
|
-
else if (bgFillTyp === 'GRADIENT_FILL') {
|
|
1394
|
-
const gradientFill = getBgGradientFill(bgPr, undefined, slideMasterContent, warpObj)
|
|
1395
|
-
if (typeof gradientFill === 'string') {
|
|
1396
|
-
background = gradientFill
|
|
1397
|
-
}
|
|
1398
|
-
else if (gradientFill) {
|
|
1399
|
-
background = gradientFill
|
|
1400
|
-
backgroundType = 'gradient'
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
else if (bgFillTyp === 'PIC_FILL') {
|
|
1404
|
-
background = await getBgPicFill(bgPr, 'slideBg', warpObj)
|
|
1405
|
-
backgroundType = 'image'
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
else {
|
|
1409
|
-
bgPr = getTextByPathList(slideLayoutContent, ['p:sldLayout', 'p:cSld', 'p:bg', 'p:bgPr'])
|
|
1410
|
-
|
|
1411
|
-
let clrMapOvr
|
|
1412
|
-
const sldClrMapOvr = getTextByPathList(slideLayoutContent, ['p:sldLayout', 'p:clrMapOvr', 'a:overrideClrMapping', 'attrs'])
|
|
1413
|
-
if (sldClrMapOvr) clrMapOvr = sldClrMapOvr
|
|
1414
|
-
else clrMapOvr = getTextByPathList(slideMasterContent, ['p:sldMaster', 'p:clrMap', 'attrs'])
|
|
1415
|
-
|
|
1416
|
-
if (bgPr) {
|
|
1417
|
-
const bgFillTyp = getFillType(bgPr)
|
|
1418
|
-
if (bgFillTyp === 'SOLID_FILL') {
|
|
1419
|
-
const sldFill = bgPr['a:solidFill']
|
|
1420
|
-
const sldBgClr = getSolidFill(sldFill, clrMapOvr, undefined, warpObj)
|
|
1421
|
-
background = `#${sldBgClr}`
|
|
1422
|
-
}
|
|
1423
|
-
else if (bgFillTyp === 'GRADIENT_FILL') {
|
|
1424
|
-
const gradientFill = getBgGradientFill(bgPr, undefined, slideMasterContent, warpObj)
|
|
1425
|
-
if (typeof gradientFill === 'string') {
|
|
1426
|
-
background = gradientFill
|
|
1427
|
-
}
|
|
1428
|
-
else if (gradientFill) {
|
|
1429
|
-
background = gradientFill
|
|
1430
|
-
backgroundType = 'gradient'
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
else if (bgFillTyp === 'PIC_FILL') {
|
|
1434
|
-
background = await getBgPicFill(bgPr, 'slideLayoutBg', warpObj)
|
|
1435
|
-
backgroundType = 'image'
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
else {
|
|
1439
|
-
bgPr = getTextByPathList(slideMasterContent, ['p:sldMaster', 'p:cSld', 'p:bg', 'p:bgPr'])
|
|
1440
|
-
|
|
1441
|
-
const clrMap = getTextByPathList(slideMasterContent, ['p:sldMaster', 'p:clrMap', 'attrs'])
|
|
1442
|
-
if (bgPr) {
|
|
1443
|
-
const bgFillTyp = getFillType(bgPr)
|
|
1444
|
-
if (bgFillTyp === 'SOLID_FILL') {
|
|
1445
|
-
const sldFill = bgPr['a:solidFill']
|
|
1446
|
-
const sldBgClr = getSolidFill(sldFill, clrMap, undefined, warpObj)
|
|
1447
|
-
background = `#${sldBgClr}`
|
|
1448
|
-
}
|
|
1449
|
-
else if (bgFillTyp === 'GRADIENT_FILL') {
|
|
1450
|
-
const gradientFill = getBgGradientFill(bgPr, undefined, slideMasterContent, warpObj)
|
|
1451
|
-
if (typeof gradientFill === 'string') {
|
|
1452
|
-
background = gradientFill
|
|
1453
|
-
}
|
|
1454
|
-
else if (gradientFill) {
|
|
1455
|
-
background = gradientFill
|
|
1456
|
-
backgroundType = 'gradient'
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
else if (bgFillTyp === 'PIC_FILL') {
|
|
1460
|
-
background = await getBgPicFill(bgPr, 'slideMasterBg', warpObj)
|
|
1461
|
-
backgroundType = 'image'
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
return {
|
|
1467
|
-
type: backgroundType,
|
|
1468
|
-
value: background,
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
function getShapeFill(node, isSvgMode) {
|
|
1473
|
-
if (getTextByPathList(node, ['p:spPr', 'a:noFill'])) {
|
|
1474
|
-
return isSvgMode ? 'none' : ''
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
let fillColor
|
|
1478
|
-
if (!fillColor) {
|
|
1479
|
-
fillColor = getTextByPathList(node, ['p:spPr', 'a:solidFill', 'a:srgbClr', 'attrs', 'val'])
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
if (!fillColor) {
|
|
1483
|
-
const schemeClr = 'a:' + getTextByPathList(node, ['p:spPr', 'a:solidFill', 'a:schemeClr', 'attrs', 'val'])
|
|
1484
|
-
fillColor = getSchemeColorFromTheme(schemeClr)
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
if (!fillColor) {
|
|
1488
|
-
const schemeClr = 'a:' + getTextByPathList(node, ['p:style', 'a:fillRef', 'a:schemeClr', 'attrs', 'val'])
|
|
1489
|
-
fillColor = getSchemeColorFromTheme(schemeClr)
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
if (fillColor) {
|
|
1493
|
-
fillColor = `#${fillColor}`
|
|
1494
|
-
|
|
1495
|
-
let lumMod = parseInt(getTextByPathList(node, ['p:spPr', 'a:solidFill', 'a:schemeClr', 'a:lumMod', 'attrs', 'val'])) / 100000
|
|
1496
|
-
let lumOff = parseInt(getTextByPathList(node, ['p:spPr', 'a:solidFill', 'a:schemeClr', 'a:lumOff', 'attrs', 'val'])) / 100000
|
|
1497
|
-
if (isNaN(lumMod)) lumMod = 1.0
|
|
1498
|
-
if (isNaN(lumOff)) lumOff = 0
|
|
1499
|
-
|
|
1500
|
-
const color = tinycolor(fillColor).toHsl()
|
|
1501
|
-
const lum = color.l * (1 + lumOff)
|
|
1502
|
-
return tinycolor({ h: color.h, s: color.s, l: lum, a: color.a }).toHexString()
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
if (isSvgMode) return 'none'
|
|
1506
|
-
return fillColor
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
function getSolidFill(solidFill) {
|
|
1510
|
-
if (!solidFill) return solidFill
|
|
1511
|
-
|
|
1512
|
-
let color = 'fff'
|
|
1513
|
-
|
|
1514
|
-
if (solidFill['a:srgbClr']) {
|
|
1515
|
-
color = getTextByPathList(solidFill['a:srgbClr'], ['attrs', 'val'])
|
|
1516
|
-
}
|
|
1517
|
-
else if (solidFill['a:schemeClr']) {
|
|
1518
|
-
const schemeClr = 'a:' + getTextByPathList(solidFill['a:schemeClr'], ['attrs', 'val'])
|
|
1519
|
-
color = getSchemeColorFromTheme(schemeClr)
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
return color
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
function getSchemeColorFromTheme(schemeClr) {
|
|
1526
|
-
switch (schemeClr) {
|
|
1527
|
-
case 'a:tx1':
|
|
1528
|
-
schemeClr = 'a:dk1'
|
|
1529
|
-
break
|
|
1530
|
-
case 'a:tx2':
|
|
1531
|
-
schemeClr = 'a:dk2'
|
|
1532
|
-
break
|
|
1533
|
-
case 'a:bg1':
|
|
1534
|
-
schemeClr = 'a:lt1'
|
|
1535
|
-
break
|
|
1536
|
-
case 'a:bg2':
|
|
1537
|
-
schemeClr = 'a:lt2'
|
|
1538
|
-
break
|
|
1539
|
-
default:
|
|
1540
|
-
break
|
|
1541
|
-
}
|
|
1542
|
-
const refNode = getTextByPathList(themeContent, ['a:theme', 'a:themeElements', 'a:clrScheme', schemeClr])
|
|
1543
|
-
let color = getTextByPathList(refNode, ['a:srgbClr', 'attrs', 'val'])
|
|
1544
|
-
if (!color) color = getTextByPathList(refNode, ['a:sysClr', 'attrs', 'lastClr'])
|
|
1545
|
-
return color
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
function extractChartData(serNode) {
|
|
1549
|
-
const dataMat = []
|
|
1550
|
-
if (!serNode) return dataMat
|
|
1551
|
-
|
|
1552
|
-
if (serNode['c:xVal']) {
|
|
1553
|
-
let dataRow = []
|
|
1554
|
-
eachElement(serNode['c:xVal']['c:numRef']['c:numCache']['c:pt'], innerNode => {
|
|
1555
|
-
dataRow.push(parseFloat(innerNode['c:v']))
|
|
1556
|
-
return ''
|
|
1557
|
-
})
|
|
1558
|
-
dataMat.push(dataRow)
|
|
1559
|
-
dataRow = []
|
|
1560
|
-
eachElement(serNode['c:yVal']['c:numRef']['c:numCache']['c:pt'], innerNode => {
|
|
1561
|
-
dataRow.push(parseFloat(innerNode['c:v']))
|
|
1562
|
-
return ''
|
|
1563
|
-
})
|
|
1564
|
-
dataMat.push(dataRow)
|
|
1565
|
-
}
|
|
1566
|
-
else {
|
|
1567
|
-
eachElement(serNode, (innerNode, index) => {
|
|
1568
|
-
const dataRow = []
|
|
1569
|
-
const colName = getTextByPathList(innerNode, ['c:tx', 'c:strRef', 'c:strCache', 'c:pt', 'c:v']) || index
|
|
1570
|
-
|
|
1571
|
-
const rowNames = {}
|
|
1572
|
-
if (getTextByPathList(innerNode, ['c:cat', 'c:strRef', 'c:strCache', 'c:pt'])) {
|
|
1573
|
-
eachElement(innerNode['c:cat']['c:strRef']['c:strCache']['c:pt'], innerNode => {
|
|
1574
|
-
rowNames[innerNode['attrs']['idx']] = innerNode['c:v']
|
|
1575
|
-
return ''
|
|
1576
|
-
})
|
|
1577
|
-
}
|
|
1578
|
-
else if (getTextByPathList(innerNode, ['c:cat', 'c:numRef', 'c:numCache', 'c:pt'])) {
|
|
1579
|
-
eachElement(innerNode['c:cat']['c:numRef']['c:numCache']['c:pt'], innerNode => {
|
|
1580
|
-
rowNames[innerNode['attrs']['idx']] = innerNode['c:v']
|
|
1581
|
-
return ''
|
|
1582
|
-
})
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
if (getTextByPathList(innerNode, ['c:val', 'c:numRef', 'c:numCache', 'c:pt'])) {
|
|
1586
|
-
eachElement(innerNode['c:val']['c:numRef']['c:numCache']['c:pt'], innerNode => {
|
|
1587
|
-
dataRow.push({
|
|
1588
|
-
x: innerNode['attrs']['idx'],
|
|
1589
|
-
y: parseFloat(innerNode['c:v']),
|
|
1590
|
-
})
|
|
1591
|
-
return ''
|
|
1592
|
-
})
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
dataMat.push({
|
|
1596
|
-
key: colName,
|
|
1597
|
-
values: dataRow,
|
|
1598
|
-
xlabels: rowNames,
|
|
1599
|
-
})
|
|
1600
|
-
return ''
|
|
1601
|
-
})
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
return dataMat
|
|
1605
|
-
}
|
|
783
|
+
}
|