pptxtojson 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptxtojson",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "A javascript tool for parsing .pptx file",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",
package/src/diagram.js CHANGED
@@ -67,10 +67,12 @@ export async function getDiagramNodeContext(node, warpObj) {
67
67
  let relationshipArray = digramResContent['Relationships']['Relationship']
68
68
  if (relationshipArray && relationshipArray.constructor !== Array) relationshipArray = [relationshipArray]
69
69
  if (relationshipArray) {
70
- for (const relationshipArrayItem of relationshipArray) {
71
- let relTarget = relationshipArrayItem['attrs']['Target']
72
- if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
73
- else relTarget = drawingTarget.replace(drawingName, '') + relTarget
70
+ for (const relationshipArrayItem of relationshipArray) {
71
+ let relTarget = relationshipArrayItem['attrs']['Target']
72
+ relTarget = relTarget.replace(/\\/g, '/')
73
+ if (relTarget.indexOf('/ppt/') === 0) relTarget = relTarget.substr(1)
74
+ else if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
75
+ else relTarget = drawingTarget.replace(drawingName, '') + relTarget
74
76
 
75
77
  diagramResObj[relationshipArrayItem['attrs']['Id']] = {
76
78
  type: relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
@@ -129,4 +131,4 @@ export function getSmartArtTextData(dataContent) {
129
131
  }
130
132
 
131
133
  return result
132
- }
134
+ }
package/src/paragraph.js CHANGED
@@ -177,12 +177,16 @@ function getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMas
177
177
  return styleNodes
178
178
  }
179
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'
180
+ function getLineSpacingValue(spacingNode, singleLineSpacingFactor = 1) {
181
+ const spcPct = getTextByPathList(spacingNode, ['a:spcPct', 'attrs', 'val'])
182
+ const spcPts = getTextByPathList(spacingNode, ['a:spcPts', 'attrs', 'val'])
183
+
184
+ if (spcPct !== undefined) {
185
+ const value = String(spcPct).trim()
186
+ const percentage = value.endsWith('%') ? Number.parseFloat(value) / 100 : Number.parseInt(value, 10) / 100000
187
+ if (Number.isFinite(percentage)) return percentage * singleLineSpacingFactor
188
+ }
189
+ if (spcPts) return parseInt(spcPts) / 100 + 'pt'
186
190
 
187
191
  return undefined
188
192
  }
@@ -205,16 +209,17 @@ function getParagraphIndentValue(styleNode, attrName) {
205
209
  return undefined
206
210
  }
207
211
 
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
212
+ export function getParagraphSpacing(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
213
+ const styleNodes = getParagraphStyleNodes(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj)
214
+ if (!styleNodes) return null
215
+
216
+ const spacing = {}
217
+ const singleLineSpacingFactor = getTextByPathList(warpObj, ['options', 'singleLineSpacingFactor'])
218
+
219
+ for (const styleNode of styleNodes) {
220
+ if (spacing.lineSpacing === undefined) {
221
+ const lineSpacing = getLineSpacingValue(styleNode['a:lnSpc'], singleLineSpacingFactor)
222
+ if (lineSpacing !== undefined) spacing.lineSpacing = lineSpacing
218
223
  }
219
224
 
220
225
  if (spacing.spaceBefore === undefined) {
package/src/pptxtojson.js CHANGED
@@ -25,10 +25,11 @@ export async function parse(file, options = {}) {
25
25
  const xmlCache = {}
26
26
  const parseOptions = {
27
27
  ...options,
28
- imageMode: options.imageMode || 'base64',
29
- videoMode: options.videoMode || 'none',
30
- audioMode: options.audioMode || 'none',
31
- }
28
+ imageMode: options.imageMode || 'base64',
29
+ videoMode: options.videoMode || 'none',
30
+ audioMode: options.audioMode || 'none',
31
+ singleLineSpacingFactor: Number.isFinite(options.singleLineSpacingFactor) && options.singleLineSpacingFactor > 0 ? options.singleLineSpacingFactor : 1,
32
+ }
32
33
 
33
34
  const zip = await JSZip.loadAsync(file)
34
35
 
@@ -129,7 +130,12 @@ async function getTheme(zip) {
129
130
  themeURI = relationshipArray['attrs']['Target']
130
131
  }
131
132
 
132
- const themeContent = await readXmlFile(zip, 'ppt/' + themeURI)
133
+ let themeContent = null
134
+ if (themeURI) {
135
+ themeURI = themeURI.replace(/\\/g, '/')
136
+ const themeFilename = themeURI.indexOf('/ppt/') === 0 ? themeURI.substr(1) : 'ppt/' + themeURI
137
+ themeContent = await readXmlFile(zip, themeFilename)
138
+ }
133
139
 
134
140
  const themeColors = []
135
141
  const clrScheme = getTextByPathList(themeContent, ['a:theme', 'a:themeElements', 'a:clrScheme'])
@@ -173,7 +179,9 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
173
179
  let relTarget = relationshipArrayItem['attrs']['Target']
174
180
  const isExternal = relationshipArrayItem['attrs']['TargetMode'] === 'External'
175
181
  if (!isExternal) {
176
- if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
182
+ relTarget = relTarget.replace(/\\/g, '/')
183
+ if (relTarget.indexOf('/ppt/') === 0) relTarget = relTarget.substr(1)
184
+ else if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
177
185
  else relTarget = 'ppt/slides/' + relTarget
178
186
  }
179
187
 
@@ -226,7 +234,9 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
226
234
  for (const relationshipArrayItem of relationshipArray) {
227
235
  const relType = relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', '')
228
236
  let relTarget = relationshipArrayItem['attrs']['Target']
229
- if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
237
+ relTarget = relTarget.replace(/\\/g, '/')
238
+ if (relTarget.indexOf('/ppt/') === 0) relTarget = relTarget.substr(1)
239
+ else if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
230
240
  else relTarget = 'ppt/slideLayouts/' + relTarget
231
241
 
232
242
  switch (relationshipArrayItem['attrs']['Type']) {
@@ -252,7 +262,9 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
252
262
  for (const relationshipArrayItem of relationshipArray) {
253
263
  const relType = relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', '')
254
264
  let relTarget = relationshipArrayItem['attrs']['Target']
255
- if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
265
+ relTarget = relTarget.replace(/\\/g, '/')
266
+ if (relTarget.indexOf('/ppt/') === 0) relTarget = relTarget.substr(1)
267
+ else if (relTarget.indexOf('../') !== -1) relTarget = relTarget.replace('../', 'ppt/')
256
268
  else relTarget = 'ppt/slideMasters/' + relTarget
257
269
 
258
270
  switch (relationshipArrayItem['attrs']['Type']) {
@@ -267,10 +279,10 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
267
279
  }
268
280
  }
269
281
 
270
- let currentThemeContent = themeContent
271
- if (themeFilename) {
272
- currentThemeContent = currentThemeContent || await readXmlFileCached(zip, themeFilename, xmlCache)
273
- const themeName = themeFilename.split('/').pop()
282
+ let currentThemeContent = themeContent
283
+ if (themeFilename) {
284
+ currentThemeContent = await readXmlFileCached(zip, themeFilename, xmlCache) || currentThemeContent
285
+ const themeName = themeFilename.split('/').pop()
274
286
  const themeResFileName = themeFilename.replace(themeName, '_rels/' + themeName) + '.rels'
275
287
  const themeResContent = await readXmlFile(zip, themeResFileName)
276
288
  if (themeResContent) {
@@ -278,9 +290,14 @@ async function processSingleSlide(zip, sldFileName, themeContent, defaultTextSty
278
290
  if (relationshipArray) {
279
291
  if (relationshipArray.constructor !== Array) relationshipArray = [relationshipArray]
280
292
  for (const relationshipArrayItem of relationshipArray) {
293
+ let relTarget = relationshipArrayItem['attrs']['Target']
294
+ relTarget = relTarget.replace(/\\/g, '/')
295
+ if (relTarget.indexOf('/ppt/') === 0) relTarget = relTarget.substr(1)
296
+ else relTarget = relTarget.replace('../', 'ppt/')
297
+
281
298
  themeResObj[relationshipArrayItem['attrs']['Id']] = {
282
299
  'type': relationshipArrayItem['attrs']['Type'].replace('http://schemas.openxmlformats.org/officeDocument/2006/relationships/', ''),
283
- 'target': relationshipArrayItem['attrs']['Target'].replace('../', 'ppt/')
300
+ 'target': relTarget
284
301
  }
285
302
  }
286
303
  }
@@ -558,6 +575,19 @@ async function processNodesInSlide(nodeKey, nodeValue, warpObj, source, groupHie
558
575
  default:
559
576
  }
560
577
 
578
+ if (json && typeof json === 'object' && !json.id) {
579
+ const id = getTextByPathList(nodeValue, ['p:nvSpPr', 'p:cNvPr', 'attrs', 'id']) ||
580
+ getTextByPathList(nodeValue, ['p:nvPicPr', 'p:cNvPr', 'attrs', 'id']) ||
581
+ getTextByPathList(nodeValue, ['p:nvCxnSpPr', 'p:cNvPr', 'attrs', 'id']) ||
582
+ getTextByPathList(nodeValue, ['p:nvGrpSpPr', 'p:cNvPr', 'attrs', 'id']) ||
583
+ getTextByPathList(nodeValue, ['p:nvGraphicFramePr', 'p:cNvPr', 'attrs', 'id']) ||
584
+ getTextByPathList(nodeValue, ['mc:Choice', 'p:sp', 'p:nvSpPr', 'p:cNvPr', 'attrs', 'id']) ||
585
+ getTextByPathList(nodeValue, ['mc:Fallback', 'p:sp', 'p:nvSpPr', 'p:cNvPr', 'attrs', 'id']) ||
586
+ getTextByPathList(nodeValue, ['mc:Fallback', 'p:nvGrpSpPr', 'p:cNvPr', 'attrs', 'id'])
587
+
588
+ json.id = id || ''
589
+ }
590
+
561
591
  return json
562
592
  }
563
593
 
@@ -795,7 +825,7 @@ async function genShape(node, slideLayoutSpNode, slideMasterSpNode, name, type,
795
825
  let content = ''
796
826
  if (node['p:txBody']) content = genTextBody(node['p:txBody'], node, slideLayoutSpNode, slideMasterSpNode, type, warpObj)
797
827
 
798
- const { borderColor, borderWidth, borderType, strokeDasharray, headEnd, tailEnd } = getBorder(node, type, warpObj)
828
+ const { borderColor, borderWidth, borderType, strokeDasharray, headEnd, tailEnd } = getBorder(node, type, warpObj)
799
829
  const fill = await getShapeFill(node, warpObj, source, {
800
830
  groupHierarchy,
801
831
  slideLayoutSpNode,
@@ -808,6 +838,7 @@ async function genShape(node, slideLayoutSpNode, slideMasterSpNode, name, type,
808
838
 
809
839
  const vAlign = getVerticalAlign(node, slideLayoutSpNode, slideMasterSpNode, type)
810
840
  const isVertical = getTextByPathList(node, ['p:txBody', 'a:bodyPr', 'attrs', 'vert']) === 'eaVert'
841
+ const wrap = getTextByPathList(node, ['p:txBody', 'a:bodyPr', 'attrs', 'wrap']) !== 'none'
811
842
  const autoFit = getTextAutoFit(node, slideLayoutSpNode, slideMasterSpNode)
812
843
  const textInset = getTextInsets(node, slideLayoutSpNode, slideMasterSpNode)
813
844
 
@@ -826,16 +857,17 @@ async function genShape(node, slideLayoutSpNode, slideMasterSpNode, name, type,
826
857
  isFlipH,
827
858
  rotate,
828
859
  vAlign,
860
+ wrap,
829
861
  name,
830
862
  order,
831
863
  }
832
864
 
833
865
  if (shadow) data.shadow = shadow
834
- if (autoFit) data.autoFit = autoFit
835
- if (link) data.link = link
836
- if (textInset) data.textInset = textInset
837
- if (headEnd) data.headEnd = headEnd
838
- if (tailEnd) data.tailEnd = tailEnd
866
+ if (autoFit) data.autoFit = autoFit
867
+ if (link) data.link = link
868
+ if (textInset) data.textInset = textInset
869
+ if (headEnd) data.headEnd = headEnd
870
+ if (tailEnd) data.tailEnd = tailEnd
839
871
 
840
872
  const isHasValidText = data.content && hasValidText(data.content)
841
873