1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699 |
- import JSZip from 'jszip'
- import { readXmlFile } from './readXmlFile'
- import { getBorder } from './border'
- import {
- getSlideBackgroundFill,
- getShapeFill,
- getSolidFill,
- getPicFill
- } from './fill'
- import { getChartInfo } from './chart'
- import { getVerticalAlign } from './align'
- import { getPosition, getSize } from './position'
- import { genTextBody } from './text'
- import { getCustomShapePath } from './shape'
- import {
- extractFileExtension,
- base64ArrayBuffer,
- getTextByPathList,
- angleToDegrees,
- getMimeType,
- isVideoLink,
- escapeHtml,
- hasValidText
- } from './utils'
- import { getShadow } from './shadow'
- import {
- getTableBorders,
- getTableCellParams,
- getTableRowParams
- } from './table'
- import { RATIO_EMUs_Points } from './constants'
- import { findOMath, latexFormart, parseOMath } from './math'
- export async function parse (file) {
- const slides = []
- const zip = await JSZip.loadAsync(file)
- const filesInfo = await getContentTypes(zip)
- const { width, height, defaultTextStyle } = await getSlideInfo(zip)
- // 获取所有主题文件
- const themeMap = await getAllThemes(zip)
- for (const filename of filesInfo.slides) {
- // 为每个幻灯片获取对应的主题
- const { themeContent, themeColors } = await getSlideTheme(
- zip,
- filename,
- themeMap
- )
- const singleSlide = await processSingleSlide(
- zip,
- filename,
- themeContent,
- defaultTextStyle
- )
- slides.push({
- ...singleSlide,
- themeColors // 为每个幻灯片添加其对应的主题颜色
- })
- }
- return {
- slides,
- size: {
- width,
- height
- }
- }
- }
- async function getSlideInfo (zip) {
- const content = await readXmlFile(zip, 'ppt/presentation.xml')
- const sldSzAttrs = content['p:presentation']['p:sldSz']['attrs']
- const defaultTextStyle = content['p:presentation']['p:defaultTextStyle']
- return {
- width: parseInt(sldSzAttrs['cx']) * RATIO_EMUs_Points,
- height: parseInt(sldSzAttrs['cy']) * RATIO_EMUs_Points,
- defaultTextStyle
- }
- }
- async function getContentTypes (zip) {
- const ContentTypesJson = await readXmlFile(zip, '[Content_Types].xml')
- const subObj = ContentTypesJson['Types']['Override']
- let slidesLocArray = []
- let slideLayoutsLocArray = []
- let themeLocArray = []
- for (const item of subObj) {
- switch (item['attrs']['ContentType']) {
- case 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml':
- slidesLocArray.push(item['attrs']['PartName'].substr(1))
- break
- case 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml':
- slideLayoutsLocArray.push(item['attrs']['PartName'].substr(1))
- break
- case 'application/vnd.openxmlformats-officedocument.theme+xml':
- themeLocArray.push(item['attrs']['PartName'].substr(1))
- break
- default:
- }
- }
- const sortSlideXml = (p1, p2) => {
- const n1 = +/(\d+)\.xml/.exec(p1)[1]
- const n2 = +/(\d+)\.xml/.exec(p2)[1]
- return n1 - n2
- }
- slidesLocArray = slidesLocArray.sort(sortSlideXml)
- slideLayoutsLocArray = slideLayoutsLocArray.sort(sortSlideXml)
- themeLocArray = themeLocArray.sort(sortSlideXml)
- return {
- slides: slidesLocArray,
- slideLayouts: slideLayoutsLocArray,
- themes: themeLocArray
- }
- }
- // 获取所有主题文件并建立映射关系
- async function getAllThemes (zip) {
- const themeMap = new Map()
- const filesInfo = await getContentTypes(zip)
- // 从 Content_Types.xml 中获取主题文件路径
- for (const themePath of filesInfo.themes) {
- const themeContent = await readXmlFile(zip, themePath)
- themeMap.set(themePath, { themeContent, masterId: null })
- }
- // 获取母版与主题的对应关系
- const preResContent = await readXmlFile(
- zip,
- 'ppt/_rels/presentation.xml.rels'
- )
- const presentationContent = await readXmlFile(zip, 'ppt/presentation.xml')
- const masterIdList = getTextByPathList(presentationContent, [
- 'p:presentation',
- 'p:sldMasterIdLst',
- 'p:sldMasterId'
- ])
- if (masterIdList) {
- const relationshipArray = preResContent['Relationships']['Relationship']
- const masters = Array.isArray(masterIdList)
- ? masterIdList
- : [masterIdList]
- for (const master of masters) {
- const masterId = master['attrs']['r:id']
- const masterRel = Array.isArray(relationshipArray)
- ? relationshipArray.find((rel) => rel['attrs']['Id'] === masterId)
- : relationshipArray['attrs']['Id'] === masterId
- ? relationshipArray
- : null
- if (masterRel) {
- const masterTarget = masterRel['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- const masterRelsPath =
- masterTarget.replace(
- 'slideMasters/slideMaster',
- 'slideMasters/_rels/slideMaster'
- ) + '.rels'
- const masterRels = await readXmlFile(zip, masterRelsPath)
- if (masterRels && masterRels['Relationships']) {
- const relationships = masterRels['Relationships']['Relationship']
- const themeRel = Array.isArray(relationships)
- ? relationships.find((rel) =>
- rel['attrs']['Type'].endsWith('/theme')
- )
- : relationships['attrs']['Type'].endsWith('/theme')
- ? relationships
- : null
- if (themeRel) {
- const themeURI = themeRel['attrs']['Target'].replace('../', '')
- const themePath = 'ppt/' + themeURI
- // 更新主题映射中的 masterId
- if (themeMap.has(themePath)) {
- const themeData = themeMap.get(themePath)
- themeData.masterId = masterId
- themeMap.set(masterTarget, themeData)
- }
- }
- }
- }
- }
- }
- return themeMap
- }
- // 获取单个幻灯片对应的主题
- async function getSlideTheme (zip, slideFilename, themeMap) {
- try {
- // 获取幻灯片的布局信息
- const slideRelsPath =
- slideFilename.replace('slides/slide', 'slides/_rels/slide') + '.rels'
- const slideRels = await readXmlFile(zip, slideRelsPath)
- if (!slideRels?.Relationships?.Relationship) {
- return { themeContent: {}, themeColors: [] }
- }
- // 获取布局文件路径
- const relationships = slideRels['Relationships']['Relationship']
- const layoutRel = Array.isArray(relationships)
- ? relationships.find((rel) =>
- rel['attrs']['Type'].endsWith('/slideLayout')
- )
- : relationships['attrs']['Type'].endsWith('/slideLayout')
- ? relationships
- : null
- if (!layoutRel) return { themeContent: {}, themeColors: [] }
- const layoutPath = 'ppt/' + layoutRel['attrs']['Target'].replace('../', '')
- const layoutRelsPath =
- layoutPath.replace(
- 'slideLayouts/slideLayout',
- 'slideLayouts/_rels/slideLayout'
- ) + '.rels'
- // 获取母版文件路径
- const layoutRels = await readXmlFile(zip, layoutRelsPath)
- if (!layoutRels?.Relationships?.Relationship) {
- return { themeContent: {}, themeColors: [] }
- }
- const masterRelationships = layoutRels['Relationships']['Relationship']
- const masterRel = Array.isArray(masterRelationships)
- ? masterRelationships.find((rel) =>
- rel['attrs']['Type'].endsWith('/slideMaster')
- )
- : masterRelationships['attrs']['Type'].endsWith('/slideMaster')
- ? masterRelationships
- : null
- if (!masterRel) return { themeContent: {}, themeColors: [] }
- const masterPath = 'ppt/' + masterRel['attrs']['Target'].replace('../', '')
- const masterRelsPath =
- masterPath.replace(
- 'slideMasters/slideMaster',
- 'slideMasters/_rels/slideMaster'
- ) + '.rels'
- // 获取主题关系
- const masterRels = await readXmlFile(zip, masterRelsPath)
- if (!masterRels?.Relationships?.Relationship) {
- return { themeContent: {}, themeColors: [] }
- }
- const themeRelationships = masterRels['Relationships']['Relationship']
- const themeRel = Array.isArray(themeRelationships)
- ? themeRelationships.find((rel) =>
- rel['attrs']['Type'].endsWith('/theme')
- )
- : themeRelationships['attrs']['Type'].endsWith('/theme')
- ? themeRelationships
- : null
- if (!themeRel) return { themeContent: {}, themeColors: [] }
- const themePath = 'ppt/' + themeRel['attrs']['Target'].replace('../', '')
- const themeData = themeMap.get(themePath)
- if (!themeData?.themeContent) return { themeContent: {}, themeColors: [] }
- // 提取主题颜色
- const themeColors = []
- const clrScheme = getTextByPathList(themeData.themeContent, [
- 'a:theme',
- 'a:themeElements',
- 'a:clrScheme'
- ])
- if (clrScheme) {
- for (let i = 1; i <= 6; i++) {
- if (clrScheme[`a:accent${i}`] === undefined) break
- const color = getTextByPathList(clrScheme, [
- `a:accent${i}`,
- 'a:srgbClr',
- 'attrs',
- 'val'
- ])
- if (color) themeColors.push('#' + color)
- }
- }
- return { themeContent: themeData.themeContent, themeColors }
- } catch (error) {
- return { themeContent: {}, themeColors: [] }
- }
- }
- async function processSingleSlide (
- zip,
- sldFileName,
- themeContent,
- defaultTextStyle
- ) {
- const resName =
- sldFileName.replace('slides/slide', 'slides/_rels/slide') + '.rels'
- const resContent = await readXmlFile(zip, resName)
- let relationshipArray = resContent['Relationships']['Relationship']
- if (relationshipArray.constructor !== Array) { relationshipArray = [relationshipArray] }
- let noteFilename = ''
- let layoutFilename = ''
- let masterFilename = ''
- let themeFilename = ''
- let diagramFilename = ''
- const slideResObj = {}
- const layoutResObj = {}
- const masterResObj = {}
- const themeResObj = {}
- const diagramResObj = {}
- for (const relationshipArrayItem of relationshipArray) {
- switch (relationshipArrayItem['attrs']['Type']) {
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout':
- layoutFilename = relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- break
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide':
- noteFilename = relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- break
- case 'http://schemas.microsoft.com/office/2007/relationships/diagramDrawing':
- diagramFilename = relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- slideResObj[relationshipArrayItem['attrs']['Id']] = {
- type: relationshipArrayItem['attrs']['Type'].replace(
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/',
- ''
- ),
- target: relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- }
- break
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image':
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart':
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink':
- default:
- slideResObj[relationshipArrayItem['attrs']['Id']] = {
- type: relationshipArrayItem['attrs']['Type'].replace(
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/',
- ''
- ),
- target: relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- }
- }
- }
- const slideNotesContent = await readXmlFile(zip, noteFilename)
- const note = getNote(slideNotesContent)
- const slideLayoutContent = await readXmlFile(zip, layoutFilename)
- const slideLayoutTables = await indexNodes(slideLayoutContent)
- const slideLayoutResFilename =
- layoutFilename.replace(
- 'slideLayouts/slideLayout',
- 'slideLayouts/_rels/slideLayout'
- ) + '.rels'
- const slideLayoutResContent = await readXmlFile(zip, slideLayoutResFilename)
- relationshipArray = slideLayoutResContent['Relationships']['Relationship']
- if (relationshipArray.constructor !== Array) { relationshipArray = [relationshipArray] }
- for (const relationshipArrayItem of relationshipArray) {
- switch (relationshipArrayItem['attrs']['Type']) {
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster':
- masterFilename = relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- break
- default:
- layoutResObj[relationshipArrayItem['attrs']['Id']] = {
- type: relationshipArrayItem['attrs']['Type'].replace(
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/',
- ''
- ),
- target: relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- }
- }
- }
- const slideMasterContent = await readXmlFile(zip, masterFilename)
- const slideMasterTextStyles = getTextByPathList(slideMasterContent, [
- 'p:sldMaster',
- 'p:txStyles'
- ])
- const slideMasterTables = indexNodes(slideMasterContent)
- const slideMasterResFilename =
- masterFilename.replace(
- 'slideMasters/slideMaster',
- 'slideMasters/_rels/slideMaster'
- ) + '.rels'
- const slideMasterResContent = await readXmlFile(zip, slideMasterResFilename)
- relationshipArray = slideMasterResContent['Relationships']['Relationship']
- if (relationshipArray.constructor !== Array) { relationshipArray = [relationshipArray] }
- for (const relationshipArrayItem of relationshipArray) {
- switch (relationshipArrayItem['attrs']['Type']) {
- case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme':
- themeFilename = relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- break
- default:
- masterResObj[relationshipArrayItem['attrs']['Id']] = {
- type: relationshipArrayItem['attrs']['Type'].replace(
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/',
- ''
- ),
- target: relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- }
- }
- }
- if (themeFilename) {
- const themeName = themeFilename.split('/').pop()
- const themeResFileName =
- themeFilename.replace(themeName, '_rels/' + themeName) + '.rels'
- const themeResContent = await readXmlFile(zip, themeResFileName)
- if (themeResContent) {
- relationshipArray = themeResContent['Relationships']['Relationship']
- if (relationshipArray) {
- if (relationshipArray.constructor !== Array) { relationshipArray = [relationshipArray] }
- for (const relationshipArrayItem of relationshipArray) {
- themeResObj[relationshipArrayItem['attrs']['Id']] = {
- type: relationshipArrayItem['attrs']['Type'].replace(
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/',
- ''
- ),
- target: relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- }
- }
- }
- }
- }
- let digramFileContent = {}
- if (diagramFilename) {
- const diagName = diagramFilename.split('/').pop()
- const diagramResFileName =
- diagramFilename.replace(diagName, '_rels/' + diagName) + '.rels'
- digramFileContent = await readXmlFile(zip, diagramFilename)
- if (digramFileContent) {
- const digramFileContentObjToStr = JSON.stringify(
- digramFileContent
- ).replace(/dsp:/g, 'p:')
- digramFileContent = JSON.parse(digramFileContentObjToStr)
- }
- const digramResContent = await readXmlFile(zip, diagramResFileName)
- if (digramResContent) {
- relationshipArray = digramResContent['Relationships']['Relationship']
- if (relationshipArray.constructor !== Array) { relationshipArray = [relationshipArray] }
- for (const relationshipArrayItem of relationshipArray) {
- diagramResObj[relationshipArrayItem['attrs']['Id']] = {
- type: relationshipArrayItem['attrs']['Type'].replace(
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/',
- ''
- ),
- target: relationshipArrayItem['attrs']['Target'].replace(
- '../',
- 'ppt/'
- )
- }
- }
- }
- }
- const tableStyles = await readXmlFile(zip, 'ppt/tableStyles.xml')
- const slideContent = await readXmlFile(zip, sldFileName)
- const nodes = slideContent['p:sld']['p:cSld']['p:spTree']
- const warpObj = {
- zip,
- slideLayoutContent,
- slideLayoutTables,
- slideMasterContent,
- slideMasterTables,
- slideContent,
- tableStyles,
- slideResObj,
- slideMasterTextStyles,
- layoutResObj,
- masterResObj,
- themeContent,
- themeResObj,
- digramFileContent,
- diagramResObj,
- defaultTextStyle
- }
- const layoutElements = await getLayoutElements(warpObj)
- const fill = await getSlideBackgroundFill(warpObj)
- const elements = []
- for (const nodeKey in nodes) {
- if (nodes[nodeKey].constructor !== Array) nodes[nodeKey] = [nodes[nodeKey]]
- for (const node of nodes[nodeKey]) {
- const ret = await processNodesInSlide(
- nodeKey,
- node,
- nodes,
- warpObj,
- 'slide'
- )
- if (ret) elements.push(ret)
- }
- }
- return {
- fill,
- elements,
- layoutElements,
- note
- }
- }
- function getNote (noteContent) {
- let text = ''
- let spNodes = getTextByPathList(noteContent, [
- 'p:notes',
- 'p:cSld',
- 'p:spTree',
- 'p:sp'
- ])
- if (!spNodes) return ''
- if (spNodes.constructor !== Array) spNodes = [spNodes]
- for (const spNode of spNodes) {
- let rNodes = getTextByPathList(spNode, ['p:txBody', 'a:p', 'a:r'])
- if (!rNodes) continue
- if (rNodes.constructor !== Array) rNodes = [rNodes]
- for (const rNode of rNodes) {
- const t = getTextByPathList(rNode, ['a:t'])
- if (t && typeof t === 'string') text += t
- }
- }
- return text
- }
- async function getLayoutElements (warpObj) {
- const elements = []
- const slideLayoutContent = warpObj['slideLayoutContent']
- const slideMasterContent = warpObj['slideMasterContent']
- const nodesSldLayout = getTextByPathList(slideLayoutContent, [
- 'p:sldLayout',
- 'p:cSld',
- 'p:spTree'
- ])
- const nodesSldMaster = getTextByPathList(slideMasterContent, [
- 'p:sldMaster',
- 'p:cSld',
- 'p:spTree'
- ])
- const showMasterSp = getTextByPathList(slideLayoutContent, [
- 'p:sldLayout',
- 'attrs',
- 'showMasterSp'
- ])
- if (nodesSldLayout) {
- for (const nodeKey in nodesSldLayout) {
- if (nodesSldLayout[nodeKey].constructor === Array) {
- for (let i = 0; i < nodesSldLayout[nodeKey].length; i++) {
- const ph = getTextByPathList(nodesSldLayout[nodeKey][i], [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph'
- ])
- if (!ph) {
- const ret = await processNodesInSlide(
- nodeKey,
- nodesSldLayout[nodeKey][i],
- nodesSldLayout,
- warpObj,
- 'slideLayoutBg'
- )
- if (ret) elements.push(ret)
- }
- }
- } else {
- const ph = getTextByPathList(nodesSldLayout[nodeKey], [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph'
- ])
- if (!ph) {
- const ret = await processNodesInSlide(
- nodeKey,
- nodesSldLayout[nodeKey],
- nodesSldLayout,
- warpObj,
- 'slideLayoutBg'
- )
- if (ret) elements.push(ret)
- }
- }
- }
- }
- if (nodesSldMaster && showMasterSp !== '0') {
- for (const nodeKey in nodesSldMaster) {
- if (nodesSldMaster[nodeKey].constructor === Array) {
- for (let i = 0; i < nodesSldMaster[nodeKey].length; i++) {
- const ph = getTextByPathList(nodesSldMaster[nodeKey][i], [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph'
- ])
- if (!ph) {
- const ret = await processNodesInSlide(
- nodeKey,
- nodesSldMaster[nodeKey][i],
- nodesSldMaster,
- warpObj,
- 'slideMasterBg'
- )
- if (ret) elements.push(ret)
- }
- }
- } else {
- const ph = getTextByPathList(nodesSldMaster[nodeKey], [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph'
- ])
- if (!ph) {
- const ret = await processNodesInSlide(
- nodeKey,
- nodesSldMaster[nodeKey],
- nodesSldMaster,
- warpObj,
- 'slideMasterBg'
- )
- if (ret) elements.push(ret)
- }
- }
- }
- }
- return elements
- }
- function indexNodes (content) {
- const keys = Object.keys(content)
- const spTreeNode = content[keys[0]]['p:cSld']['p:spTree']
- const idTable = {}
- const idxTable = {}
- const typeTable = {}
- for (const key in spTreeNode) {
- if (key === 'p:nvGrpSpPr' || key === 'p:grpSpPr') continue
- const targetNode = spTreeNode[key]
- if (targetNode.constructor === Array) {
- for (const targetNodeItem of targetNode) {
- const nvSpPrNode = targetNodeItem['p:nvSpPr']
- const id = getTextByPathList(nvSpPrNode, ['p:cNvPr', 'attrs', 'id'])
- const idx = getTextByPathList(nvSpPrNode, [
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'idx'
- ])
- const type = getTextByPathList(nvSpPrNode, [
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'type'
- ])
- if (id) idTable[id] = targetNodeItem
- if (idx) idxTable[idx] = targetNodeItem
- if (type) typeTable[type] = targetNodeItem
- }
- } else {
- const nvSpPrNode = targetNode['p:nvSpPr']
- const id = getTextByPathList(nvSpPrNode, ['p:cNvPr', 'attrs', 'id'])
- const idx = getTextByPathList(nvSpPrNode, [
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'idx'
- ])
- const type = getTextByPathList(nvSpPrNode, [
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'type'
- ])
- if (id) idTable[id] = targetNode
- if (idx) idxTable[idx] = targetNode
- if (type) typeTable[type] = targetNode
- }
- }
- return { idTable, idxTable, typeTable }
- }
- async function processNodesInSlide (nodeKey, nodeValue, nodes, warpObj, source) {
- let json
- switch (nodeKey) {
- case 'p:sp': // Shape, Text
- json = await processSpNode(nodeValue, nodes, warpObj, source)
- break
- case 'p:cxnSp': // Shape, Text
- json = await processCxnSpNode(nodeValue, nodes, warpObj, source)
- break
- case 'p:pic': // Image, Video, Audio
- json = await processPicNode(nodeValue, warpObj, source)
- break
- case 'p:graphicFrame': // Chart, Diagram, Table
- json = await processGraphicFrameNode(nodeValue, warpObj, source)
- break
- case 'p:grpSp':
- json = await processGroupSpNode(nodeValue, warpObj, source)
- break
- case 'mc:AlternateContent':
- if (
- getTextByPathList(nodeValue, ['mc:Fallback', 'p:grpSpPr', 'a:xfrm'])
- ) {
- json = await processGroupSpNode(
- getTextByPathList(nodeValue, ['mc:Fallback']),
- warpObj,
- source
- )
- } else if (getTextByPathList(nodeValue, ['mc:Choice'])) {
- json = await processMathNode(nodeValue, warpObj, source)
- }
- break
- default:
- }
- return json
- }
- async function processMathNode (node, warpObj, source) {
- const choice = getTextByPathList(node, ['mc:Choice'])
- const fallback = getTextByPathList(node, ['mc:Fallback'])
- const order = node['attrs']['order']
- const xfrmNode = getTextByPathList(choice, ['p:sp', 'p:spPr', 'a:xfrm'])
- const { top, left } = getPosition(xfrmNode, undefined, undefined)
- const { width, height } = getSize(xfrmNode, undefined, undefined)
- const oMath = findOMath(choice)[0]
- const latex = latexFormart(parseOMath(oMath))
- const blipFill = getTextByPathList(fallback, [
- 'p:sp',
- 'p:spPr',
- 'a:blipFill'
- ])
- const picBase64 = await getPicFill(source, blipFill, warpObj)
- return {
- type: 'math',
- top,
- left,
- width,
- height,
- latex,
- picBase64,
- order
- }
- }
- async function processGroupSpNode (node, warpObj, source) {
- const order = node['attrs']['order']
- const xfrmNode = getTextByPathList(node, ['p:grpSpPr', 'a:xfrm'])
- if (!xfrmNode) return null
- const x = parseInt(xfrmNode['a:off']['attrs']['x']) * RATIO_EMUs_Points
- const y = parseInt(xfrmNode['a:off']['attrs']['y']) * RATIO_EMUs_Points
- const chx = parseInt(xfrmNode['a:chOff']['attrs']['x']) * RATIO_EMUs_Points
- const chy = parseInt(xfrmNode['a:chOff']['attrs']['y']) * RATIO_EMUs_Points
- const cx = parseInt(xfrmNode['a:ext']['attrs']['cx']) * RATIO_EMUs_Points
- const cy = parseInt(xfrmNode['a:ext']['attrs']['cy']) * RATIO_EMUs_Points
- const chcx = parseInt(xfrmNode['a:chExt']['attrs']['cx']) * RATIO_EMUs_Points
- const chcy = parseInt(xfrmNode['a:chExt']['attrs']['cy']) * RATIO_EMUs_Points
- const isFlipV = getTextByPathList(xfrmNode, ['attrs', 'flipV']) === '1'
- const isFlipH = getTextByPathList(xfrmNode, ['attrs', 'flipH']) === '1'
- let rotate = getTextByPathList(xfrmNode, ['attrs', 'rot']) || 0
- if (rotate) rotate = angleToDegrees(rotate)
- const ws = cx / chcx
- const hs = cy / chcy
- const elements = []
- for (const nodeKey in node) {
- if (node[nodeKey].constructor === Array) {
- for (const item of node[nodeKey]) {
- const ret = await processNodesInSlide(
- nodeKey,
- item,
- node,
- warpObj,
- source
- )
- if (ret) {
- // 如果是嵌套的组合,需要调整其子元素的位置和大小
- if (ret.type === 'group') {
- ret.elements = ret.elements.map((element) => ({
- ...element,
- left: element.left * ws,
- top: element.top * hs,
- width: element.width * ws,
- height: element.height * hs
- }))
- }
- elements.push(ret)
- }
- }
- } else {
- const ret = await processNodesInSlide(
- nodeKey,
- node[nodeKey],
- node,
- warpObj,
- source
- )
- if (ret) {
- // 如果是嵌套的组合,需要调整其子元素的位置和大小
- if (ret.type === 'group') {
- ret.elements = ret.elements.map((element) => ({
- ...element,
- left: element.left * ws,
- top: element.top * hs,
- width: element.width * ws,
- height: element.height * hs
- }))
- }
- elements.push(ret)
- }
- }
- }
- return {
- type: 'group',
- top: y,
- left: x,
- width: cx,
- height: cy,
- rotate,
- order,
- isFlipV,
- isFlipH,
- elements: elements.map((element) => ({
- ...element,
- left: (element.left - chx) * ws,
- top: (element.top - chy) * hs,
- width: element.width * ws,
- height: element.height * hs
- }))
- }
- }
- async function processSpNode (node, pNode, warpObj, source) {
- const name = getTextByPathList(node, [
- 'p:nvSpPr',
- 'p:cNvPr',
- 'attrs',
- 'name'
- ])
- const idx = getTextByPathList(node, [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'idx'
- ])
- let type = getTextByPathList(node, [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'type'
- ])
- const order = getTextByPathList(node, ['attrs', 'order'])
- let slideLayoutSpNode, slideMasterSpNode
- if (type) {
- if (idx) {
- slideLayoutSpNode = warpObj['slideLayoutTables']['typeTable'][type]
- slideMasterSpNode = warpObj['slideMasterTables']['typeTable'][type]
- } else {
- slideLayoutSpNode = warpObj['slideLayoutTables']['typeTable'][type]
- slideMasterSpNode = warpObj['slideMasterTables']['typeTable'][type]
- }
- } else if (idx) {
- slideLayoutSpNode = warpObj['slideLayoutTables']['idxTable'][idx]
- slideMasterSpNode = warpObj['slideMasterTables']['idxTable'][idx]
- }
- if (!type) {
- const txBoxVal = getTextByPathList(node, [
- 'p:nvSpPr',
- 'p:cNvSpPr',
- 'attrs',
- 'txBox'
- ])
- if (txBoxVal === '1') type = 'text'
- }
- if (!type) {
- type = getTextByPathList(slideLayoutSpNode, [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'type'
- ])
- }
- if (!type) {
- type = getTextByPathList(slideMasterSpNode, [
- 'p:nvSpPr',
- 'p:nvPr',
- 'p:ph',
- 'attrs',
- 'type'
- ])
- }
- if (!type) {
- if (source === 'diagramBg') type = 'diagram'
- else type = 'obj'
- }
- return await genShape(
- node,
- pNode,
- slideLayoutSpNode,
- slideMasterSpNode,
- name,
- type,
- order,
- warpObj,
- source
- )
- }
- async function processCxnSpNode (node, pNode, warpObj, source) {
- const name = node['p:nvCxnSpPr']['p:cNvPr']['attrs']['name']
- const type =
- node['p:nvCxnSpPr']['p:nvPr']['p:ph'] === undefined
- ? undefined
- : node['p:nvSpPr']['p:nvPr']['p:ph']['attrs']['type']
- const order = node['attrs']['order']
- return await genShape(
- node,
- pNode,
- undefined,
- undefined,
- name,
- type,
- order,
- warpObj,
- source
- )
- }
- async function genShape (
- node,
- pNode,
- slideLayoutSpNode,
- slideMasterSpNode,
- name,
- type,
- order,
- warpObj,
- source
- ) {
- const xfrmList = ['p:spPr', 'a:xfrm']
- const slideXfrmNode = getTextByPathList(node, xfrmList)
- const slideLayoutXfrmNode = getTextByPathList(slideLayoutSpNode, xfrmList)
- const slideMasterXfrmNode = getTextByPathList(slideMasterSpNode, xfrmList)
- const shapType = getTextByPathList(node, [
- 'p:spPr',
- 'a:prstGeom',
- 'attrs',
- 'prst'
- ])
- const custShapType = getTextByPathList(node, ['p:spPr', 'a:custGeom'])
- const { top, left } = getPosition(
- slideXfrmNode,
- slideLayoutXfrmNode,
- slideMasterXfrmNode
- )
- const { width, height } = getSize(
- slideXfrmNode,
- slideLayoutXfrmNode,
- slideMasterXfrmNode
- )
- const isFlipV = getTextByPathList(slideXfrmNode, ['attrs', 'flipV']) === '1'
- const isFlipH = getTextByPathList(slideXfrmNode, ['attrs', 'flipH']) === '1'
- const rotate = angleToDegrees(
- getTextByPathList(slideXfrmNode, ['attrs', 'rot'])
- )
- const txtXframeNode = getTextByPathList(node, ['p:txXfrm'])
- let txtRotate
- if (txtXframeNode) {
- const txtXframeRot = getTextByPathList(txtXframeNode, ['attrs', 'rot'])
- if (txtXframeRot) txtRotate = angleToDegrees(txtXframeRot) + 90
- } else txtRotate = rotate
- let content = ''
- if (node['p:txBody']) {
- content = genTextBody(
- node['p:txBody'],
- node,
- slideLayoutSpNode,
- type,
- warpObj
- )
- }
- const { borderColor, borderWidth, borderType, strokeDasharray } = getBorder(
- node,
- type,
- warpObj
- )
- const fill =
- (await getShapeFill(node, pNode, undefined, warpObj, source)) || ''
- let shadow
- const outerShdwNode = getTextByPathList(node, [
- 'p:spPr',
- 'a:effectLst',
- 'a:outerShdw'
- ])
- if (outerShdwNode) shadow = getShadow(outerShdwNode, warpObj)
- const vAlign = getVerticalAlign(
- node,
- slideLayoutSpNode,
- slideMasterSpNode,
- type
- )
- const isVertical =
- getTextByPathList(node, ['p:txBody', 'a:bodyPr', 'attrs', 'vert']) ===
- 'eaVert'
- const data = {
- left,
- top,
- width,
- height,
- borderColor,
- borderWidth,
- borderType,
- borderStrokeDasharray: strokeDasharray,
- fill,
- content,
- isFlipV,
- isFlipH,
- rotate,
- vAlign,
- name,
- order
- }
- if (shadow) data.shadow = shadow
- if (custShapType && type !== 'diagram') {
- const ext = getTextByPathList(slideXfrmNode, ['a:ext', 'attrs'])
- const w = parseInt(ext['cx']) * RATIO_EMUs_Points
- const h = parseInt(ext['cy']) * RATIO_EMUs_Points
- const d = getCustomShapePath(custShapType, w, h)
- if (data.content && !hasValidText(data.content)) data.content = ''
- return {
- ...data,
- type: 'shape',
- shapType: 'custom',
- path: d
- }
- }
- if (shapType && (type === 'obj' || !type)) {
- if (data.content && !hasValidText(data.content)) data.content = ''
- return {
- ...data,
- type: 'shape',
- shapType
- }
- }
- return {
- ...data,
- type: 'text',
- isVertical,
- rotate: txtRotate
- }
- }
- async function processPicNode (node, warpObj, source) {
- let resObj
- if (source === 'slideMasterBg') resObj = warpObj['masterResObj']
- else if (source === 'slideLayoutBg') resObj = warpObj['layoutResObj']
- else resObj = warpObj['slideResObj']
- const order = node['attrs']['order']
- const rid = node['p:blipFill']['a:blip']['attrs']['r:embed']
- const imgName = resObj[rid]['target']
- const imgFileExt = extractFileExtension(imgName).toLowerCase()
- const zip = warpObj['zip']
- const imgArrayBuffer = await zip.file(imgName).async('arraybuffer')
- const xfrmNode = node['p:spPr']['a:xfrm']
- const mimeType = getMimeType(imgFileExt)
- const { top, left } = getPosition(xfrmNode, undefined, undefined)
- const { width, height } = getSize(xfrmNode, undefined, undefined)
- const src = `data:${mimeType};base64,${base64ArrayBuffer(imgArrayBuffer)}`
- const isFlipV = getTextByPathList(xfrmNode, ['attrs', 'flipV']) === '1'
- const isFlipH = getTextByPathList(xfrmNode, ['attrs', 'flipH']) === '1'
- let rotate = 0
- const rotateNode = getTextByPathList(node, [
- 'p:spPr',
- 'a:xfrm',
- 'attrs',
- 'rot'
- ])
- if (rotateNode) rotate = angleToDegrees(rotateNode)
- const videoNode = getTextByPathList(node, [
- 'p:nvPicPr',
- 'p:nvPr',
- 'a:videoFile'
- ])
- let videoRid,
- videoFile,
- videoFileExt,
- videoMimeType,
- uInt8ArrayVideo,
- videoBlob
- let isVdeoLink = false
- if (videoNode) {
- videoRid = videoNode['attrs']['r:link']
- videoFile = resObj[videoRid]['target']
- if (isVideoLink(videoFile)) {
- videoFile = escapeHtml(videoFile)
- isVdeoLink = true
- } else {
- videoFileExt = extractFileExtension(videoFile).toLowerCase()
- if (
- videoFileExt === 'mp4' ||
- videoFileExt === 'webm' ||
- videoFileExt === 'ogg'
- ) {
- uInt8ArrayVideo = await zip.file(videoFile).async('arraybuffer')
- videoMimeType = getMimeType(videoFileExt)
- videoBlob = URL.createObjectURL(
- new Blob([uInt8ArrayVideo], {
- type: videoMimeType
- })
- )
- }
- }
- }
- const audioNode = getTextByPathList(node, [
- 'p:nvPicPr',
- 'p:nvPr',
- 'a:audioFile'
- ])
- let audioRid, audioFile, audioFileExt, uInt8ArrayAudio, audioBlob
- if (audioNode) {
- audioRid = audioNode['attrs']['r:link']
- audioFile = resObj[audioRid]['target']
- audioFileExt = extractFileExtension(audioFile).toLowerCase()
- if (
- audioFileExt === 'mp3' ||
- audioFileExt === 'wav' ||
- audioFileExt === 'ogg'
- ) {
- uInt8ArrayAudio = await zip.file(audioFile).async('arraybuffer')
- audioBlob = URL.createObjectURL(new Blob([uInt8ArrayAudio]))
- }
- }
- if (videoNode && !isVdeoLink) {
- return {
- type: 'video',
- top,
- left,
- width,
- height,
- rotate,
- blob: videoBlob,
- order
- }
- }
- if (videoNode && isVdeoLink) {
- return {
- type: 'video',
- top,
- left,
- width,
- height,
- rotate,
- src: videoFile,
- order
- }
- }
- if (audioNode) {
- return {
- type: 'audio',
- top,
- left,
- width,
- height,
- rotate,
- blob: audioBlob,
- order
- }
- }
- let rect
- const srcRectAttrs = getTextByPathList(node, [
- 'p:blipFill',
- 'a:srcRect',
- 'attrs'
- ])
- if (
- srcRectAttrs &&
- (srcRectAttrs.t || srcRectAttrs.b || srcRectAttrs.l || srcRectAttrs.r)
- ) {
- rect = {}
- if (srcRectAttrs.t) rect.t = srcRectAttrs.t / 1000
- if (srcRectAttrs.b) rect.b = srcRectAttrs.b / 1000
- if (srcRectAttrs.l) rect.l = srcRectAttrs.l / 1000
- if (srcRectAttrs.r) rect.r = srcRectAttrs.r / 1000
- }
- const geom =
- getTextByPathList(node, ['p:spPr', 'a:prstGeom', 'attrs', 'prst']) ||
- 'rect'
- const { borderColor, borderWidth, borderType, strokeDasharray } = getBorder(
- node,
- undefined,
- warpObj
- )
- return {
- type: 'image',
- top,
- left,
- width,
- height,
- rotate,
- src,
- isFlipV,
- isFlipH,
- order,
- rect,
- geom,
- borderColor,
- borderWidth,
- borderType,
- borderStrokeDasharray: strokeDasharray
- }
- }
- async function processGraphicFrameNode (node, warpObj, source) {
- const graphicTypeUri = getTextByPathList(node, [
- 'a:graphic',
- 'a:graphicData',
- 'attrs',
- 'uri'
- ])
- let result
- switch (graphicTypeUri) {
- case 'http://schemas.openxmlformats.org/drawingml/2006/table':
- result = await genTable(node, warpObj)
- break
- case 'http://schemas.openxmlformats.org/drawingml/2006/chart':
- result = await genChart(node, warpObj)
- break
- case 'http://schemas.openxmlformats.org/drawingml/2006/diagram':
- result = await genDiagram(node, warpObj)
- break
- case 'http://schemas.openxmlformats.org/presentationml/2006/ole':
- let oleObjNode = getTextByPathList(node, [
- 'a:graphic',
- 'a:graphicData',
- 'mc:AlternateContent',
- 'mc:Fallback',
- 'p:oleObj'
- ])
- if (!oleObjNode) {
- oleObjNode = getTextByPathList(node, [
- 'a:graphic',
- 'a:graphicData',
- 'p:oleObj'
- ])
- }
- if (oleObjNode) { result = await processGroupSpNode(oleObjNode, warpObj, source) }
- break
- default:
- }
- return result
- }
- async function genTable (node, warpObj) {
- const order = node['attrs']['order']
- const tableNode = getTextByPathList(node, [
- 'a:graphic',
- 'a:graphicData',
- 'a:tbl'
- ])
- const xfrmNode = getTextByPathList(node, ['p:xfrm'])
- const { top, left } = getPosition(xfrmNode, undefined, undefined)
- const { width, height } = getSize(xfrmNode, undefined, undefined)
- const getTblPr = getTextByPathList(node, [
- 'a:graphic',
- 'a:graphicData',
- 'a:tbl',
- 'a:tblPr'
- ])
- let getColsGrid = getTextByPathList(node, [
- 'a:graphic',
- 'a:graphicData',
- 'a:tbl',
- 'a:tblGrid',
- 'a:gridCol'
- ])
- if (getColsGrid.constructor !== Array) getColsGrid = [getColsGrid]
- const colWidths = []
- if (getColsGrid) {
- for (const item of getColsGrid) {
- const colWidthParam = getTextByPathList(item, ['attrs', 'w']) || 0
- const colWidth = parseInt(colWidthParam) * RATIO_EMUs_Points
- colWidths.push(colWidth)
- }
- }
- const firstRowAttr = getTblPr['attrs']
- ? getTblPr['attrs']['firstRow']
- : undefined
- const firstColAttr = getTblPr['attrs']
- ? getTblPr['attrs']['firstCol']
- : undefined
- const lastRowAttr = getTblPr['attrs']
- ? getTblPr['attrs']['lastRow']
- : undefined
- const lastColAttr = getTblPr['attrs']
- ? getTblPr['attrs']['lastCol']
- : undefined
- const bandRowAttr = getTblPr['attrs']
- ? getTblPr['attrs']['bandRow']
- : undefined
- const bandColAttr = getTblPr['attrs']
- ? getTblPr['attrs']['bandCol']
- : undefined
- const tblStylAttrObj = {
- isFrstRowAttr: firstRowAttr && firstRowAttr === '1' ? 1 : 0,
- isFrstColAttr: firstColAttr && firstColAttr === '1' ? 1 : 0,
- isLstRowAttr: lastRowAttr && lastRowAttr === '1' ? 1 : 0,
- isLstColAttr: lastColAttr && lastColAttr === '1' ? 1 : 0,
- isBandRowAttr: bandRowAttr && bandRowAttr === '1' ? 1 : 0,
- isBandColAttr: bandColAttr && bandColAttr === '1' ? 1 : 0
- }
- let thisTblStyle
- const tbleStyleId = getTblPr['a:tableStyleId']
- if (tbleStyleId) {
- const tbleStylList = warpObj['tableStyles']['a:tblStyleLst']['a:tblStyle']
- if (tbleStylList) {
- if (tbleStylList.constructor === Array) {
- for (let k = 0; k < tbleStylList.length; k++) {
- if (tbleStylList[k]['attrs']['styleId'] === tbleStyleId) {
- thisTblStyle = tbleStylList[k]
- }
- }
- } else {
- if (tbleStylList['attrs']['styleId'] === tbleStyleId) {
- thisTblStyle = tbleStylList
- }
- }
- }
- }
- if (thisTblStyle) thisTblStyle['tblStylAttrObj'] = tblStylAttrObj
- let borders = {}
- const tblStyl = getTextByPathList(thisTblStyle, ['a:wholeTbl', 'a:tcStyle'])
- const tblBorderStyl = getTextByPathList(tblStyl, ['a:tcBdr'])
- if (tblBorderStyl) borders = getTableBorders(tblBorderStyl, warpObj)
- let tbl_bgcolor = ''
- let tbl_bgFillschemeClr = getTextByPathList(thisTblStyle, [
- 'a:tblBg',
- 'a:fillRef'
- ])
- if (tbl_bgFillschemeClr) {
- tbl_bgcolor = getSolidFill(
- tbl_bgFillschemeClr,
- undefined,
- undefined,
- warpObj
- )
- }
- if (tbl_bgFillschemeClr === undefined) {
- tbl_bgFillschemeClr = getTextByPathList(thisTblStyle, [
- 'a:wholeTbl',
- 'a:tcStyle',
- 'a:fill',
- 'a:solidFill'
- ])
- tbl_bgcolor = getSolidFill(
- tbl_bgFillschemeClr,
- undefined,
- undefined,
- warpObj
- )
- }
- let trNodes = tableNode['a:tr']
- if (trNodes.constructor !== Array) trNodes = [trNodes]
- const data = []
- const rowHeights = []
- for (let i = 0; i < trNodes.length; i++) {
- const trNode = trNodes[i]
- const rowHeightParam = getTextByPathList(trNodes[i], ['attrs', 'h']) || 0
- const rowHeight = parseInt(rowHeightParam) * RATIO_EMUs_Points
- rowHeights.push(rowHeight)
- const { fillColor, fontColor, fontBold } = getTableRowParams(
- trNodes,
- i,
- tblStylAttrObj,
- thisTblStyle,
- warpObj
- )
- const tcNodes = trNode['a:tc']
- const tr = []
- if (tcNodes.constructor === Array) {
- for (let j = 0; j < tcNodes.length; j++) {
- const tcNode = tcNodes[j]
- let a_sorce
- if (j === 0 && tblStylAttrObj['isFrstColAttr'] === 1) {
- a_sorce = 'a:firstCol'
- if (
- tblStylAttrObj['isLstRowAttr'] === 1 &&
- i === trNodes.length - 1 &&
- getTextByPathList(thisTblStyle, ['a:seCell'])
- ) {
- a_sorce = 'a:seCell'
- } else if (
- tblStylAttrObj['isFrstRowAttr'] === 1 &&
- i === 0 &&
- getTextByPathList(thisTblStyle, ['a:neCell'])
- ) {
- a_sorce = 'a:neCell'
- }
- } else if (
- j > 0 &&
- tblStylAttrObj['isBandColAttr'] === 1 &&
- !(tblStylAttrObj['isFrstColAttr'] === 1 && i === 0) &&
- !(tblStylAttrObj['isLstRowAttr'] === 1 && i === trNodes.length - 1) &&
- j !== tcNodes.length - 1
- ) {
- if (j % 2 !== 0) {
- let aBandNode = getTextByPathList(thisTblStyle, ['a:band2V'])
- if (aBandNode === undefined) {
- aBandNode = getTextByPathList(thisTblStyle, ['a:band1V'])
- if (aBandNode) a_sorce = 'a:band2V'
- } else a_sorce = 'a:band2V'
- }
- }
- if (j === tcNodes.length - 1 && tblStylAttrObj['isLstColAttr'] === 1) {
- a_sorce = 'a:lastCol'
- if (
- tblStylAttrObj['isLstRowAttr'] === 1 &&
- i === trNodes.length - 1 &&
- getTextByPathList(thisTblStyle, ['a:swCell'])
- ) {
- a_sorce = 'a:swCell'
- } else if (
- tblStylAttrObj['isFrstRowAttr'] === 1 &&
- i === 0 &&
- getTextByPathList(thisTblStyle, ['a:nwCell'])
- ) {
- a_sorce = 'a:nwCell'
- }
- }
- const text = genTextBody(
- tcNode['a:txBody'],
- tcNode,
- undefined,
- undefined,
- warpObj
- )
- const cell = await getTableCellParams(
- tcNode,
- thisTblStyle,
- a_sorce,
- warpObj
- )
- const td = { text }
- if (cell.rowSpan) td.rowSpan = cell.rowSpan
- if (cell.colSpan) td.colSpan = cell.colSpan
- if (cell.vMerge) td.vMerge = cell.vMerge
- if (cell.hMerge) td.hMerge = cell.hMerge
- if (cell.fontBold || fontBold) td.fontBold = cell.fontBold || fontBold
- if (cell.fontColor || fontColor) { td.fontColor = cell.fontColor || fontColor }
- if (cell.fillColor || fillColor || tbl_bgcolor) { td.fillColor = cell.fillColor || fillColor || tbl_bgcolor }
- if (cell.borders) td.borders = cell.borders
- tr.push(td)
- }
- } else {
- let a_sorce
- if (
- tblStylAttrObj['isFrstColAttr'] === 1 &&
- tblStylAttrObj['isLstRowAttr'] !== 1
- ) {
- a_sorce = 'a:firstCol'
- } else if (
- tblStylAttrObj['isBandColAttr'] === 1 &&
- tblStylAttrObj['isLstRowAttr'] !== 1
- ) {
- let aBandNode = getTextByPathList(thisTblStyle, ['a:band2V'])
- if (!aBandNode) {
- aBandNode = getTextByPathList(thisTblStyle, ['a:band1V'])
- if (aBandNode) a_sorce = 'a:band2V'
- } else a_sorce = 'a:band2V'
- }
- if (
- tblStylAttrObj['isLstColAttr'] === 1 &&
- tblStylAttrObj['isLstRowAttr'] !== 1
- ) {
- a_sorce = 'a:lastCol'
- }
- const text = genTextBody(
- tcNodes['a:txBody'],
- tcNodes,
- undefined,
- undefined,
- warpObj
- )
- const cell = await getTableCellParams(
- tcNodes,
- thisTblStyle,
- a_sorce,
- warpObj
- )
- const td = { text }
- if (cell.rowSpan) td.rowSpan = cell.rowSpan
- if (cell.colSpan) td.colSpan = cell.colSpan
- if (cell.vMerge) td.vMerge = cell.vMerge
- if (cell.hMerge) td.hMerge = cell.hMerge
- if (cell.fontBold || fontBold) td.fontBold = cell.fontBold || fontBold
- if (cell.fontColor || fontColor) { td.fontColor = cell.fontColor || fontColor }
- if (cell.fillColor || fillColor || tbl_bgcolor) { td.fillColor = cell.fillColor || fillColor || tbl_bgcolor }
- if (cell.borders) td.borders = cell.borders
- tr.push(td)
- }
- data.push(tr)
- }
- return {
- type: 'table',
- top,
- left,
- width,
- height,
- data,
- order,
- borders,
- rowHeights,
- colWidths
- }
- }
- async function genChart (node, warpObj) {
- const order = node['attrs']['order']
- const xfrmNode = getTextByPathList(node, ['p:xfrm'])
- const { top, left } = getPosition(xfrmNode, undefined, undefined)
- const { width, height } = getSize(xfrmNode, undefined, undefined)
- const rid = node['a:graphic']['a:graphicData']['c:chart']['attrs']['r:id']
- let refName = getTextByPathList(warpObj['slideResObj'], [rid, 'target'])
- if (!refName) { refName = getTextByPathList(warpObj['layoutResObj'], [rid, 'target']) }
- if (!refName) { refName = getTextByPathList(warpObj['masterResObj'], [rid, 'target']) }
- if (!refName) return {}
- const content = await readXmlFile(warpObj['zip'], refName)
- const plotArea = getTextByPathList(content, [
- 'c:chartSpace',
- 'c:chart',
- 'c:plotArea'
- ])
- const chart = getChartInfo(plotArea, warpObj)
- if (!chart) return {}
- const data = {
- type: 'chart',
- top,
- left,
- width,
- height,
- data: chart.data,
- colors: chart.colors,
- chartType: chart.type,
- order
- }
- if (chart.marker !== undefined) data.marker = chart.marker
- if (chart.barDir !== undefined) data.barDir = chart.barDir
- if (chart.holeSize !== undefined) data.holeSize = chart.holeSize
- if (chart.grouping !== undefined) data.grouping = chart.grouping
- if (chart.style !== undefined) data.style = chart.style
- return data
- }
- async function genDiagram (node, warpObj) {
- const order = node['attrs']['order']
- const xfrmNode = getTextByPathList(node, ['p:xfrm'])
- const { left, top } = getPosition(xfrmNode, undefined, undefined)
- const { width, height } = getSize(xfrmNode, undefined, undefined)
- const dgmDrwSpArray = getTextByPathList(warpObj['digramFileContent'], [
- 'p:drawing',
- 'p:spTree',
- 'p:sp'
- ])
- const elements = []
- if (dgmDrwSpArray) {
- for (const item of dgmDrwSpArray) {
- const el = await processSpNode(item, node, warpObj, 'diagramBg')
- if (el) elements.push(el)
- }
- }
- return {
- type: 'diagram',
- left,
- top,
- width,
- height,
- elements,
- order
- }
- }
|