pptxtojson 0.0.12 → 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.
@@ -0,0 +1,41 @@
1
+ import * as txml from 'txml/dist/txml.mjs'
2
+
3
+ export function simplifyLostLess(children, parentAttributes = {}) {
4
+ const out = {}
5
+ if (!children.length) return out
6
+
7
+ if (children.length === 1 && typeof children[0] === 'string') {
8
+ return Object.keys(parentAttributes).length ? {
9
+ attrs: parentAttributes,
10
+ value: children[0],
11
+ } : children[0]
12
+ }
13
+ for (const child of children) {
14
+ if (typeof child !== 'object') return
15
+ if (child.tagName === '?xml') continue
16
+
17
+ if (!out[child.tagName]) out[child.tagName] = []
18
+
19
+ const kids = simplifyLostLess(child.children || [], child.attributes)
20
+ out[child.tagName].push(kids)
21
+
22
+ if (Object.keys(child.attributes).length) {
23
+ kids.attrs = child.attributes
24
+ }
25
+ }
26
+ for (const child in out) {
27
+ if (out[child].length === 1) out[child] = out[child][0]
28
+ }
29
+
30
+ return out
31
+ }
32
+
33
+ export async function readXmlFile(zip, filename) {
34
+ try {
35
+ const data = await zip.file(filename).async('string')
36
+ return simplifyLostLess(txml.parse(data))
37
+ }
38
+ catch {
39
+ return null
40
+ }
41
+ }
@@ -0,0 +1,24 @@
1
+ import { getTextByPathList } from './utils'
2
+
3
+ export function getSchemeColorFromTheme(schemeClr, warpObj) {
4
+ switch (schemeClr) {
5
+ case 'tx1':
6
+ schemeClr = 'a:dk1'
7
+ break
8
+ case 'tx2':
9
+ schemeClr = 'a:dk2'
10
+ break
11
+ case 'bg1':
12
+ schemeClr = 'a:lt1'
13
+ break
14
+ case 'bg2':
15
+ schemeClr = 'a:lt2'
16
+ break
17
+ default:
18
+ break
19
+ }
20
+ const refNode = getTextByPathList(warpObj['themeContent'], ['a:theme', 'a:themeElements', 'a:clrScheme', schemeClr])
21
+ let color = getTextByPathList(refNode, ['a:srgbClr', 'attrs', 'val'])
22
+ if (!color && refNode) color = getTextByPathList(refNode, ['a:sysClr', 'attrs', 'lastClr'])
23
+ return color
24
+ }
package/src/shadow.js ADDED
@@ -0,0 +1,18 @@
1
+ import { getSolidFill } from './fill'
2
+
3
+ export function getShadow(node, warpObj, slideFactor) {
4
+ const chdwClrNode = getSolidFill(node, undefined, undefined, warpObj)
5
+ const outerShdwAttrs = node['attrs']
6
+ const dir = (outerShdwAttrs['dir']) ? (parseInt(outerShdwAttrs['dir']) / 60000) : 0
7
+ const dist = parseInt(outerShdwAttrs['dist']) * slideFactor
8
+ const blurRad = outerShdwAttrs['blurRad'] ? (parseInt(outerShdwAttrs['blurRad']) * slideFactor) : ''
9
+ const vx = dist * Math.sin(dir * Math.PI / 180)
10
+ const hx = dist * Math.cos(dir * Math.PI / 180)
11
+
12
+ return {
13
+ h: hx,
14
+ v: vx,
15
+ blur: blurRad,
16
+ color: '#' + chdwClrNode,
17
+ }
18
+ }
package/src/shape.js ADDED
@@ -0,0 +1,178 @@
1
+ import { getTextByPathList } from './utils'
2
+
3
+ export function shapeArc(cX, cY, rX, rY, stAng, endAng, isClose) {
4
+ let dData
5
+ let angle = stAng
6
+ if (endAng >= stAng) {
7
+ while (angle <= endAng) {
8
+ const radians = angle * (Math.PI / 180)
9
+ const x = cX + Math.cos(radians) * rX
10
+ const y = cY + Math.sin(radians) * rY
11
+ if (angle === stAng) {
12
+ dData = ' M' + x + ' ' + y
13
+ }
14
+ dData += ' L' + x + ' ' + y
15
+ angle++
16
+ }
17
+ }
18
+ else {
19
+ while (angle > endAng) {
20
+ const radians = angle * (Math.PI / 180)
21
+ const x = cX + Math.cos(radians) * rX
22
+ const y = cY + Math.sin(radians) * rY
23
+ if (angle === stAng) {
24
+ dData = ' M ' + x + ' ' + y
25
+ }
26
+ dData += ' L ' + x + ' ' + y
27
+ angle--
28
+ }
29
+ }
30
+ dData += (isClose ? ' z' : '')
31
+ return dData
32
+ }
33
+
34
+ export function getCustomShapePath(custShapType, w, h) {
35
+ const pathLstNode = getTextByPathList(custShapType, ['a:pathLst'])
36
+ const pathNodes = getTextByPathList(pathLstNode, ['a:path'])
37
+ const maxX = parseInt(pathNodes['attrs']['w'])
38
+ const maxY = parseInt(pathNodes['attrs']['h'])
39
+ const cX = (1 / maxX) * w
40
+ const cY = (1 / maxY) * h
41
+ let d = ''
42
+
43
+ let moveToNode = getTextByPathList(pathNodes, ['a:moveTo'])
44
+
45
+ const lnToNodes = pathNodes['a:lnTo']
46
+ let cubicBezToNodes = pathNodes['a:cubicBezTo']
47
+ const arcToNodes = pathNodes['a:arcTo']
48
+ let closeNode = getTextByPathList(pathNodes, ['a:close'])
49
+ if (!Array.isArray(moveToNode)) moveToNode = [moveToNode]
50
+
51
+ const multiSapeAry = []
52
+ if (moveToNode.length > 0) {
53
+ Object.keys(moveToNode).forEach(key => {
54
+ const moveToPtNode = moveToNode[key]['a:pt']
55
+ if (moveToPtNode) {
56
+ Object.keys(moveToPtNode).forEach(key => {
57
+ const moveToNoPt = moveToPtNode[key]
58
+ const spX = moveToNoPt['attrs', 'x']
59
+ const spY = moveToNoPt['attrs', 'y']
60
+
61
+ multiSapeAry.push({
62
+ type: 'movto',
63
+ x: spX,
64
+ y: spY,
65
+ })
66
+ })
67
+ }
68
+ })
69
+ if (lnToNodes) {
70
+ Object.keys(lnToNodes).forEach(key => {
71
+ const lnToPtNode = lnToNodes[key]['a:pt']
72
+ if (lnToPtNode) {
73
+ Object.keys(lnToPtNode).forEach(key => {
74
+ const lnToNoPt = lnToPtNode[key]
75
+ const ptX = lnToNoPt['attrs', 'x']
76
+ const ptY = lnToNoPt['attrs', 'y']
77
+ multiSapeAry.push({
78
+ type: 'lnto',
79
+ x: ptX,
80
+ y: ptY,
81
+ })
82
+ })
83
+ }
84
+ })
85
+ }
86
+ if (cubicBezToNodes) {
87
+ const cubicBezToPtNodesAry = []
88
+ if (!Array.isArray(cubicBezToNodes)) {
89
+ cubicBezToNodes = [cubicBezToNodes]
90
+ }
91
+ Object.keys(cubicBezToNodes).forEach(key => {
92
+ cubicBezToPtNodesAry.push(cubicBezToNodes[key]['a:pt'])
93
+ })
94
+
95
+ cubicBezToPtNodesAry.forEach(key => {
96
+ const pts_ary = []
97
+ key.forEach(pt => {
98
+ const pt_obj = {
99
+ x: pt['attrs']['x'],
100
+ y: pt['attrs']['y'],
101
+ }
102
+ pts_ary.push(pt_obj)
103
+ })
104
+ multiSapeAry.push({
105
+ type: 'cubicBezTo',
106
+ cubBzPt: pts_ary
107
+ })
108
+ })
109
+ }
110
+ if (arcToNodes) {
111
+ const arcToNodesAttrs = arcToNodes['attrs']
112
+ const hR = arcToNodesAttrs['hR']
113
+ const wR = arcToNodesAttrs['wR']
114
+ const stAng = arcToNodesAttrs['stAng']
115
+ const swAng = arcToNodesAttrs['swAng']
116
+ let shftX = 0
117
+ let shftY = 0
118
+ const arcToPtNode = getTextByPathList(arcToNodes, ['a:pt', 'attrs'])
119
+ if (arcToPtNode) {
120
+ shftX = arcToPtNode['x']
121
+ shftY = arcToPtNode['y']
122
+ }
123
+ multiSapeAry.push({
124
+ type: 'arcTo',
125
+ hR: hR,
126
+ wR: wR,
127
+ stAng: stAng,
128
+ swAng: swAng,
129
+ shftX: shftX,
130
+ shftY: shftY,
131
+ })
132
+ }
133
+ if (closeNode) {
134
+ if (!Array.isArray(closeNode)) closeNode = [closeNode]
135
+ Object.keys(closeNode).forEach(() => {
136
+ multiSapeAry.push({
137
+ type: 'close',
138
+ })
139
+ })
140
+ }
141
+
142
+ let k = 0
143
+ while (k < multiSapeAry.length) {
144
+
145
+ if (multiSapeAry[k].type === 'movto') {
146
+ const spX = parseInt(multiSapeAry[k].x) * cX
147
+ const spY = parseInt(multiSapeAry[k].y) * cY
148
+ d += ' M' + spX + ',' + spY
149
+ }
150
+ else if (multiSapeAry[k].type === 'lnto') {
151
+ const Lx = parseInt(multiSapeAry[k].x) * cX
152
+ const Ly = parseInt(multiSapeAry[k].y) * cY
153
+ d += ' L' + Lx + ',' + Ly
154
+ }
155
+ else if (multiSapeAry[k].type === 'cubicBezTo') {
156
+ const Cx1 = parseInt(multiSapeAry[k].cubBzPt[0].x) * cX
157
+ const Cy1 = parseInt(multiSapeAry[k].cubBzPt[0].y) * cY
158
+ const Cx2 = parseInt(multiSapeAry[k].cubBzPt[1].x) * cX
159
+ const Cy2 = parseInt(multiSapeAry[k].cubBzPt[1].y) * cY
160
+ const Cx3 = parseInt(multiSapeAry[k].cubBzPt[2].x) * cX
161
+ const Cy3 = parseInt(multiSapeAry[k].cubBzPt[2].y) * cY
162
+ d += ' C' + Cx1 + ',' + Cy1 + ' ' + Cx2 + ',' + Cy2 + ' ' + Cx3 + ',' + Cy3
163
+ }
164
+ else if (multiSapeAry[k].type === 'arcTo') {
165
+ const hR = parseInt(multiSapeAry[k].hR) * cX
166
+ const wR = parseInt(multiSapeAry[k].wR) * cY
167
+ const stAng = parseInt(multiSapeAry[k].stAng) / 60000
168
+ const swAng = parseInt(multiSapeAry[k].swAng) / 60000
169
+ const endAng = stAng + swAng
170
+ d += shapeArc(wR, hR, wR, hR, stAng, endAng, false)
171
+ }
172
+ else if (multiSapeAry[k].type === 'close') d += 'z'
173
+ k++
174
+ }
175
+ }
176
+
177
+ return d
178
+ }
package/src/text.js ADDED
@@ -0,0 +1,131 @@
1
+ import { getHorizontalAlign } from './align'
2
+ import { getTextByPathList } from './utils'
3
+
4
+ import {
5
+ getFontType,
6
+ getFontColor,
7
+ getFontSize,
8
+ getFontBold,
9
+ getFontItalic,
10
+ getFontDecoration,
11
+ getFontSpace,
12
+ getFontSubscript,
13
+ getFontShadow,
14
+ } from './fontStyle'
15
+
16
+ export function genTextBody(textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj, fontsizeFactor, slideFactor) {
17
+ if (!textBodyNode) return ''
18
+
19
+ let text = ''
20
+ const slideMasterTextStyles = warpObj['slideMasterTextStyles']
21
+
22
+ const pNode = textBodyNode['a:p']
23
+ const pNodes = pNode.constructor === Array ? pNode : [pNode]
24
+
25
+ let isList = ''
26
+
27
+ for (const pNode of pNodes) {
28
+ let rNode = pNode['a:r']
29
+ let fldNode = pNode['a:fld']
30
+ let brNode = pNode['a:br']
31
+ if (rNode) {
32
+ rNode = (rNode.constructor === Array) ? rNode : [rNode]
33
+
34
+ if (fldNode) {
35
+ fldNode = (fldNode.constructor === Array) ? fldNode : [fldNode]
36
+ rNode = rNode.concat(fldNode)
37
+ }
38
+ if (brNode) {
39
+ brNode = (brNode.constructor === Array) ? brNode : [brNode]
40
+ brNode.forEach(item => item.type = 'br')
41
+
42
+ if (brNode.length > 1) brNode.shift()
43
+ rNode = rNode.concat(brNode)
44
+ rNode.sort((a, b) => {
45
+ if (!a.attrs || !b.attrs) return true
46
+ return a.attrs.order - b.attrs.order
47
+ })
48
+ }
49
+ }
50
+
51
+ const align = getHorizontalAlign(pNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles)
52
+
53
+ const listType = getListType(pNode)
54
+ if (listType) {
55
+ if (!isList) {
56
+ text += `<${listType}>`
57
+ isList = listType
58
+ }
59
+ else if (isList && isList !== listType) {
60
+ text += `</${isList}>`
61
+ text += `<${listType}>`
62
+ isList = listType
63
+ }
64
+ text += `<li style="text-align: ${align};">`
65
+ }
66
+ else {
67
+ if (isList) {
68
+ text += `</${isList}>`
69
+ isList = ''
70
+ }
71
+ text += `<p style="text-align: ${align};">`
72
+ }
73
+
74
+ if (!rNode) text += genSpanElement(pNode, slideLayoutSpNode, type, warpObj, fontsizeFactor, slideFactor)
75
+ else {
76
+ for (const rNodeItem of rNode) {
77
+ text += genSpanElement(rNodeItem, slideLayoutSpNode, type, warpObj, fontsizeFactor, slideFactor)
78
+ }
79
+ }
80
+
81
+ if (listType) text += '</li>'
82
+ else text += '</p>'
83
+ }
84
+ return text
85
+ }
86
+
87
+ export function getListType(node) {
88
+ const pPrNode = node['a:pPr']
89
+ if (!pPrNode) return ''
90
+
91
+ if (pPrNode['a:buChar']) return 'ul'
92
+ if (pPrNode['a:buAutoNum']) return 'ol'
93
+
94
+ return ''
95
+ }
96
+
97
+ export function genSpanElement(node, slideLayoutSpNode, type, warpObj, fontsizeFactor, slideFactor) {
98
+ const slideMasterTextStyles = warpObj['slideMasterTextStyles']
99
+
100
+ let text = node['a:t']
101
+ if (typeof text !== 'string') text = getTextByPathList(node, ['a:fld', 'a:t'])
102
+ if (typeof text !== 'string') text = '&nbsp;'
103
+
104
+ let styleText = ''
105
+ const fontColor = getFontColor(node)
106
+ const fontSize = getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles, fontsizeFactor)
107
+ const fontType = getFontType(node, type, warpObj)
108
+ const fontBold = getFontBold(node)
109
+ const fontItalic = getFontItalic(node)
110
+ const fontDecoration = getFontDecoration(node)
111
+ const fontSpace = getFontSpace(node, fontsizeFactor)
112
+ const shadow = getFontShadow(node, warpObj, slideFactor)
113
+ const subscript = getFontSubscript(node)
114
+
115
+ if (fontColor) styleText += `color: ${fontColor};`
116
+ if (fontSize) styleText += `font-size: ${fontSize};`
117
+ if (fontType) styleText += `font-family: ${fontType};`
118
+ if (fontBold) styleText += `font-weight: ${fontBold};`
119
+ if (fontItalic) styleText += `font-style: ${fontItalic};`
120
+ if (fontDecoration) styleText += `text-decoration: ${fontDecoration};`
121
+ if (fontSpace) styleText += `letter-spacing: ${fontSpace};`
122
+ if (subscript) styleText += `vertical-align: ${subscript}; font-size: smaller;`
123
+ if (shadow) styleText += `text-shadow: ${shadow};`
124
+
125
+ const linkID = getTextByPathList(node, ['a:rPr', 'a:hlinkClick', 'attrs', 'r:id'])
126
+ if (linkID) {
127
+ const linkURL = warpObj['slideResObj'][linkID]['target']
128
+ return `<span style="${styleText}"><a href="${linkURL}" target="_blank">${text.replace(/\s/i, '&nbsp;')}</a></span>`
129
+ }
130
+ return `<span style="${styleText}">${text.replace(/\s/i, '&nbsp;')}</span>`
131
+ }
package/src/utils.js CHANGED
@@ -39,16 +39,16 @@ export function extractFileExtension(filename) {
39
39
  return filename.substr((~-filename.lastIndexOf('.') >>> 0) + 2)
40
40
  }
41
41
 
42
- export function eachElement(node, doFunction) {
42
+ export function eachElement(node, func) {
43
43
  if (!node) return node
44
44
 
45
45
  let result = ''
46
46
  if (node.constructor === Array) {
47
47
  for (let i = 0; i < node.length; i++) {
48
- result += doFunction(node[i], i)
48
+ result += func(node[i], i)
49
49
  }
50
50
  }
51
- else result += doFunction(node, 0)
51
+ else result += func(node, 0)
52
52
 
53
53
  return result
54
54
  }
@@ -135,4 +135,17 @@ export function getMimeType(imgFileExt) {
135
135
  default:
136
136
  }
137
137
  return mimeType
138
+ }
139
+
140
+ export function isVideoLink(vdoFile) {
141
+ const urlRegex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
142
+ return urlRegex.test(vdoFile)
143
+ }
144
+
145
+ export function toHex(n) {
146
+ let hex = n.toString(16)
147
+ while (hex.length < 2) {
148
+ hex = '0' + hex
149
+ }
150
+ return hex
138
151
  }
package/test.pptx CHANGED
Binary file
package/test2.pptx ADDED
Binary file
package/test3.pptx ADDED
Binary file