UNPKG

offices-viewer

Version:

## Current Renderable File Types

1,892 lines (1,768 loc) 65.5 kB
// @ts-nocheck import * as colz from 'colz/dist/colz.cjs'; // MIT https://github.com/g21589/PPTX2HTML var _order = 1; var themeContent = null; var styleTable = {}; var chartID = 0; var MsgQueue = new Array(); var titleFontSize = 42; var bodyFontSize = 20; var otherFontSize = 16; export function setThemeContent(data) { themeContent = data; } function tXml(S) { 'use strict'; var openBracket = '<'; var openBracketCC = '<'.charCodeAt(0); var closeBracket = '>'; var closeBracketCC = '>'.charCodeAt(0); var minus = '-'; var minusCC = '-'.charCodeAt(0); var slash = '/'; var slashCC = '/'.charCodeAt(0); var exclamation = '!'; var exclamationCC = '!'.charCodeAt(0); var singleQuote = "'"; var singleQuoteCC = "'".charCodeAt(0); var doubleQuote = '"'; var doubleQuoteCC = '"'.charCodeAt(0); var questionMark = '?'; var questionMarkCC = '?'.charCodeAt(0); /** * returns text until the first nonAlphebetic letter */ var nameSpacer = '\r\n\t>/= '; var pos = 0; /** * Parsing a list of entries */ function parseChildren() { var children = []; while (S[pos]) { if (S.charCodeAt(pos) == openBracketCC) { if (S.charCodeAt(pos + 1) === slashCC) { // </ //while (S[pos]!=='>') { pos++; } pos = S.indexOf(closeBracket, pos); return children; } else if (S.charCodeAt(pos + 1) === exclamationCC) { // <! or <!-- if (S.charCodeAt(pos + 2) == minusCC) { // comment support while ( !( S.charCodeAt(pos) === closeBracketCC && S.charCodeAt(pos - 1) == minusCC && S.charCodeAt(pos - 2) == minusCC && pos != -1 ) ) { pos = S.indexOf(closeBracket, pos + 1); } if (pos === -1) { pos = S.length; } } else { // doctype support pos += 2; for (; S.charCodeAt(pos) !== closeBracketCC; pos++) {} } pos++; continue; } else if (S.charCodeAt(pos + 1) === questionMarkCC) { // <? // XML header support pos = S.indexOf(closeBracket, pos); pos++; continue; } pos++; var startNamePos = pos; for (; nameSpacer.indexOf(S[pos]) === -1; pos++) {} var node_tagName = S.slice(startNamePos, pos); // Parsing attributes var attrFound = false; var node_attributes = {}; for (; S.charCodeAt(pos) !== closeBracketCC; pos++) { var c = S.charCodeAt(pos); if ((c > 64 && c < 91) || (c > 96 && c < 123)) { startNamePos = pos; for (; nameSpacer.indexOf(S[pos]) === -1; pos++) {} var name = S.slice(startNamePos, pos); // search beginning of the string var code = S.charCodeAt(pos); while (code !== singleQuoteCC && code !== doubleQuoteCC) { pos++; code = S.charCodeAt(pos); } var startChar = S[pos]; var startStringPos = ++pos; pos = S.indexOf(startChar, startStringPos); var value = S.slice(startStringPos, pos); if (!attrFound) { node_attributes = {}; attrFound = true; } node_attributes[name] = value; } } // Optional parsing of children if (S.charCodeAt(pos - 1) !== slashCC) { pos++; var node_children = parseChildren(); } children.push({ children: node_children, tagName: node_tagName, attrs: node_attributes, }); } else { var startTextPos = pos; pos = S.indexOf(openBracket, pos) - 1; // Skip characters until '<' if (pos === -2) { pos = S.length; } var text = S.slice(startTextPos, pos + 1); if (text.trim().length > 0) { children.push(text); } } pos++; } return children; } _order = 1; return simplefy(parseChildren()); } function simplefy(children) { var node = {}; if (children === undefined) { return {}; } // Text node (e.g. <t>This is text.</t>) if (children.length === 1 && typeof children[0] == 'string') { return children[0]; } // map each object children.forEach(function (child) { if (!node[child.tagName]) { node[child.tagName] = []; } if (typeof child === 'object') { var kids = simplefy(child.children); if (typeof kids === 'object') { if (child.attrs) { kids.attrs = child.attrs; } if (kids['attrs'] === undefined) { kids['attrs'] = { order: _order }; } else { kids['attrs']['order'] = _order; } } _order++; node[child.tagName].push(kids); } }); for (var i in node) { if (node[i].length == 1) { node[i] = node[i][0]; } } return node; } function indexNodes(content) { var keys = Object.keys(content); var spTreeNode = content[keys[0]]['p:cSld']['p:spTree']; var idTable = {}; var idxTable = {}; var typeTable = {}; for (var key in spTreeNode) { if (key == 'p:nvGrpSpPr' || key == 'p:grpSpPr') { continue; } var targetNode = spTreeNode[key]; if (targetNode.constructor === Array) { for (var i = 0; i < targetNode.length; i++) { var nvSpPrNode = targetNode[i]['p:nvSpPr']; var id = getTextByPathList(nvSpPrNode, ['p:cNvPr', 'attrs', 'id']); var idx = getTextByPathList(nvSpPrNode, [ 'p:nvPr', 'p:ph', 'attrs', 'idx', ]); var type = getTextByPathList(nvSpPrNode, [ 'p:nvPr', 'p:ph', 'attrs', 'type', ]); if (id !== undefined) { idTable[id] = targetNode[i]; } if (idx !== undefined) { idxTable[idx] = targetNode[i]; } if (type !== undefined) { typeTable[type] = targetNode[i]; } } } else { var nvSpPrNode = targetNode['p:nvSpPr']; var id = getTextByPathList(nvSpPrNode, ['p:cNvPr', 'attrs', 'id']); var idx = getTextByPathList(nvSpPrNode, [ 'p:nvPr', 'p:ph', 'attrs', 'idx', ]); var type = getTextByPathList(nvSpPrNode, [ 'p:nvPr', 'p:ph', 'attrs', 'type', ]); if (id !== undefined) { idTable[id] = targetNode; } if (idx !== undefined) { idxTable[idx] = targetNode; } if (type !== undefined) { typeTable[type] = targetNode; } } } return { idTable: idTable, idxTable: idxTable, typeTable: typeTable }; } export function base64ArrayBuffer(arrayBuffer) { var base64 = ''; var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var bytes = new Uint8Array(arrayBuffer); var byteLength = bytes.byteLength; var byteRemainder = byteLength % 3; var mainLength = byteLength - byteRemainder; var a, b, c, d; var chunk; for (var i = 0; i < mainLength; i = i + 3) { chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; a = (chunk & 16515072) >> 18; b = (chunk & 258048) >> 12; c = (chunk & 4032) >> 6; d = chunk & 63; base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; } if (byteRemainder == 1) { chunk = bytes[mainLength]; a = (chunk & 252) >> 2; b = (chunk & 3) << 4; base64 += encodings[a] + encodings[b] + '=='; } else if (byteRemainder == 2) { chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; a = (chunk & 64512) >> 10; b = (chunk & 1008) >> 4; c = (chunk & 15) << 2; base64 += encodings[a] + encodings[b] + encodings[c] + '='; } return base64; } function readXmlFile(zip, filename) { return tXml(zip.file(filename).asText()); } export function getContentTypes(zip) { var ContentTypesJson = readXmlFile(zip, '[Content_Types].xml'); var subObj = ContentTypesJson['Types']['Override']; var slidesLocArray = []; var slideLayoutsLocArray = []; for (var i = 0; i < subObj.length; i++) { switch (subObj[i]['attrs']['ContentType']) { case 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml': slidesLocArray.push(subObj[i]['attrs']['PartName'].substr(1)); break; case 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml': slideLayoutsLocArray.push(subObj[i]['attrs']['PartName'].substr(1)); break; default: } } return { slides: slidesLocArray, slideLayouts: slideLayoutsLocArray, }; } export function getSlideSize(zip) { if (!zip.files['ppt/presentation.xml']) { return { width: 960, height: 720, }; } // Pixel = EMUs * Resolution / 914400; (Resolution = 96) var content = readXmlFile(zip, 'ppt/presentation.xml'); var sldSzAttrs = content['p:presentation']['p:sldSz']['attrs']; return { width: (parseInt(sldSzAttrs['cx']) * 96) / 914400, height: (parseInt(sldSzAttrs['cy']) * 96) / 914400, }; } export function loadTheme(zip) { var preResContent = readXmlFile(zip, 'ppt/_rels/presentation.xml.rels'); var relationshipArray = preResContent['Relationships']['Relationship']; var themeURI = undefined; if (relationshipArray.constructor === Array) { for (var i = 0; i < relationshipArray.length; i++) { if ( relationshipArray[i]['attrs']['Type'] === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' ) { themeURI = relationshipArray[i]['attrs']['Target']; break; } } } else if ( relationshipArray['attrs']['Type'] === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' ) { themeURI = relationshipArray['attrs']['Target']; } if (themeURI === undefined) { throw Error("Can't open theme file."); } return readXmlFile(zip, 'ppt/' + themeURI); } export function processSingleSlide(zip, sldFileName, index, slideSize) { // self.postMessage({ // "type": "INFO", // "data": "Processing slide" + (index + 1) // }); // =====< Step 1 >===== // Read relationship filename of the slide (Get slideLayoutXX.xml) // @sldFileName: ppt/slides/slide1.xml // @resName: ppt/slides/_rels/slide1.xml.rels var resName = sldFileName.replace('slides/slide', 'slides/_rels/slide') + '.rels'; var resContent = readXmlFile(zip, resName); var RelationshipArray = resContent['Relationships']['Relationship']; var layoutFilename = ''; var slideResObj = {}; if (RelationshipArray.constructor === Array) { for (var i = 0; i < RelationshipArray.length; i++) { switch (RelationshipArray[i]['attrs']['Type']) { case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout': layoutFilename = RelationshipArray[i]['attrs']['Target'].replace( '../', 'ppt/', ); break; case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide': 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[RelationshipArray[i]['attrs']['Id']] = { type: RelationshipArray[i]['attrs']['Type'].replace( 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/', '', ), target: RelationshipArray[i]['attrs']['Target'].replace( '../', 'ppt/', ), }; } } } else { layoutFilename = RelationshipArray['attrs']['Target'].replace( '../', 'ppt/', ); } // Open slideLayoutXX.xml var slideLayoutContent = readXmlFile(zip, layoutFilename); var slideLayoutTables = indexNodes(slideLayoutContent); // =====< Step 2 >===== // Read slide master filename of the slidelayout (Get slideMasterXX.xml) // @resName: ppt/slideLayouts/slideLayout1.xml // @masterName: ppt/slideLayouts/_rels/slideLayout1.xml.rels var slideLayoutResFilename = layoutFilename.replace( 'slideLayouts/slideLayout', 'slideLayouts/_rels/slideLayout', ) + '.rels'; var slideLayoutResContent = readXmlFile(zip, slideLayoutResFilename); RelationshipArray = slideLayoutResContent['Relationships']['Relationship']; var masterFilename = ''; if (RelationshipArray.constructor === Array) { for (var i = 0; i < RelationshipArray.length; i++) { switch (RelationshipArray[i]['attrs']['Type']) { case 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster': masterFilename = RelationshipArray[i]['attrs']['Target'].replace( '../', 'ppt/', ); break; default: } } } else { masterFilename = RelationshipArray['attrs']['Target'].replace( '../', 'ppt/', ); } // Open slideMasterXX.xml var slideMasterContent = readXmlFile(zip, masterFilename); var slideMasterTextStyles = getTextByPathList(slideMasterContent, [ 'p:sldMaster', 'p:txStyles', ]); var slideMasterTables = indexNodes(slideMasterContent); // =====< Step 3 >===== var slideContent = readXmlFile(zip, sldFileName); var nodes = slideContent['p:sld']['p:cSld']['p:spTree']; var warpObj = { zip: zip, slideLayoutTables: slideLayoutTables, slideMasterTables: slideMasterTables, slideResObj: slideResObj, slideMasterTextStyles: slideMasterTextStyles, }; var bgColor = getSlideBackgroundFill( slideContent, slideLayoutContent, slideMasterContent, ); var result = "<section style='width:" + slideSize.width + 'px; height:' + slideSize.height + 'px; background-color: #' + bgColor + "'>"; for (var nodeKey in nodes) { if (nodes[nodeKey].constructor === Array) { for (var i = 0; i < nodes[nodeKey].length; i++) { result += processNodesInSlide(nodeKey, nodes[nodeKey][i], warpObj); } } else { result += processNodesInSlide(nodeKey, nodes[nodeKey], warpObj); } } return result + '</section>'; } function getTextByPathList(node, path) { if (path.constructor !== Array) { throw Error('Error of path type! path is not array.'); } if (node === undefined) { return undefined; } var l = path.length; for (var i = 0; i < l; i++) { node = node[path[i]]; if (node === undefined) { return undefined; } } return node; } function getSolidFill(solidFill) { if (solidFill === undefined) { return undefined; } var color = 'FFF'; if (solidFill['a:srgbClr'] !== undefined) { color = getTextByPathList(solidFill['a:srgbClr'], ['attrs', 'val']); } else if (solidFill['a:schemeClr'] !== undefined) { var schemeClr = 'a:' + getTextByPathList(solidFill['a:schemeClr'], ['attrs', 'val']); color = getSchemeColorFromTheme(schemeClr); } return color; } function processNodesInSlide(nodeKey, nodeValue, warpObj) { var result = ''; switch (nodeKey) { case 'p:sp': // Shape, Text result = processSpNode(nodeValue, warpObj); break; case 'p:cxnSp': // Shape, Text (with connection) result = processCxnSpNode(nodeValue, warpObj); break; case 'p:pic': // Picture result = processPicNode(nodeValue, warpObj); break; case 'p:graphicFrame': // Chart, Diagram, Table result = processGraphicFrameNode(nodeValue, warpObj); break; case 'p:grpSp': // 群組 result = processGroupSpNode(nodeValue, warpObj); break; default: } return result; } function processSpNode(node, warpObj) { /* * 958 <xsd:complexType name="CT_GvmlShape"> * 959 <xsd:sequence> * 960 <xsd:element name="nvSpPr" type="CT_GvmlShapeNonVisual" minOccurs="1" maxOccurs="1"/> * 961 <xsd:element name="spPr" type="CT_ShapeProperties" minOccurs="1" maxOccurs="1"/> * 962 <xsd:element name="txSp" type="CT_GvmlTextShape" minOccurs="0" maxOccurs="1"/> * 963 <xsd:element name="style" type="CT_ShapeStyle" minOccurs="0" maxOccurs="1"/> * 964 <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/> * 965 </xsd:sequence> * 966 </xsd:complexType> */ var id = node['p:nvSpPr']['p:cNvPr']['attrs']['id']; var name = node['p:nvSpPr']['p:cNvPr']['attrs']['name']; var idx = node['p:nvSpPr']['p:nvPr']['p:ph'] === undefined ? undefined : node['p:nvSpPr']['p:nvPr']['p:ph']['attrs']['idx']; var type = node['p:nvSpPr']['p:nvPr']['p:ph'] === undefined ? undefined : node['p:nvSpPr']['p:nvPr']['p:ph']['attrs']['type']; var order = node['attrs']['order']; var slideLayoutSpNode = undefined; var slideMasterSpNode = undefined; if (type !== undefined) { if (idx !== undefined) { slideLayoutSpNode = warpObj['slideLayoutTables']['typeTable'][type]; slideMasterSpNode = warpObj['slideMasterTables']['typeTable'][type]; } else { slideLayoutSpNode = warpObj['slideLayoutTables']['typeTable'][type]; slideMasterSpNode = warpObj['slideMasterTables']['typeTable'][type]; } } else { if (idx !== undefined) { slideLayoutSpNode = warpObj['slideLayoutTables']['idxTable'][idx]; slideMasterSpNode = warpObj['slideMasterTables']['idxTable'][idx]; } else { // Nothing } } if (type === undefined) { type = getTextByPathList(slideLayoutSpNode, [ 'p:nvSpPr', 'p:nvPr', 'p:ph', 'attrs', 'type', ]); if (type === undefined) { type = getTextByPathList(slideMasterSpNode, [ 'p:nvSpPr', 'p:nvPr', 'p:ph', 'attrs', 'type', ]); } } return genShape( node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, order, warpObj, ); } function processCxnSpNode(node, warpObj) { var id = node['p:nvCxnSpPr']['p:cNvPr']['attrs']['id']; var name = node['p:nvCxnSpPr']['p:cNvPr']['attrs']['name']; //var idx = (node["p:nvCxnSpPr"]["p:nvPr"]["p:ph"] === undefined) ? undefined : node["p:nvSpPr"]["p:nvPr"]["p:ph"]["attrs"]["idx"]; //var type = (node["p:nvCxnSpPr"]["p:nvPr"]["p:ph"] === undefined) ? undefined : node["p:nvSpPr"]["p:nvPr"]["p:ph"]["attrs"]["type"]; //<p:cNvCxnSpPr>(<p:cNvCxnSpPr>, <a:endCxn>) var order = node['attrs']['order']; return genShape( node, undefined, undefined, id, name, undefined, undefined, order, warpObj, ); } function genShape( node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, order, warpObj, ) { var xfrmList = ['p:spPr', 'a:xfrm']; var slideXfrmNode = getTextByPathList(node, xfrmList); var slideLayoutXfrmNode = getTextByPathList(slideLayoutSpNode, xfrmList); var slideMasterXfrmNode = getTextByPathList(slideMasterSpNode, xfrmList); var result = ''; var shapType = getTextByPathList(node, [ 'p:spPr', 'a:prstGeom', 'attrs', 'prst', ]); var isFlipV = false; if ( getTextByPathList(slideXfrmNode, ['attrs', 'flipV']) === '1' || getTextByPathList(slideXfrmNode, ['attrs', 'flipH']) === '1' ) { isFlipV = true; } if (shapType !== undefined) { var off = getTextByPathList(slideXfrmNode, ['a:off', 'attrs']); var x = (parseInt(off['x']) * 96) / 914400; var y = (parseInt(off['y']) * 96) / 914400; var ext = getTextByPathList(slideXfrmNode, ['a:ext', 'attrs']); var w = (parseInt(ext['cx']) * 96) / 914400; var h = (parseInt(ext['cy']) * 96) / 914400; result += "<svg class='drawing' _id='" + id + "' _idx='" + idx + "' _type='" + type + "' _name='" + name + "' style='" + getPosition(slideXfrmNode, undefined, undefined) + getSize(slideXfrmNode, undefined, undefined) + ' z-index: ' + order + ';' + "'>"; // Fill Color var fillColor = getShapeFill(node, true); // Border Color var border = getBorder(node, true); var headEndNodeAttrs = getTextByPathList(node, [ 'p:spPr', 'a:ln', 'a:headEnd', 'attrs', ]); var tailEndNodeAttrs = getTextByPathList(node, [ 'p:spPr', 'a:ln', 'a:tailEnd', 'attrs', ]); // type: none, triangle, stealth, diamond, oval, arrow if ( (headEndNodeAttrs !== undefined && (headEndNodeAttrs['type'] === 'triangle' || headEndNodeAttrs['type'] === 'arrow')) || (tailEndNodeAttrs !== undefined && (tailEndNodeAttrs['type'] === 'triangle' || tailEndNodeAttrs['type'] === 'arrow')) ) { var triangleMarker = '<defs><marker id="markerTriangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse" markerUnits="strokeWidth"><path d="M 0 0 L 10 5 L 0 10 z" /></marker></defs>'; result += triangleMarker; } switch (shapType) { case 'accentBorderCallout1': case 'accentBorderCallout2': case 'accentBorderCallout3': case 'accentCallout1': case 'accentCallout2': case 'accentCallout3': case 'actionButtonBackPrevious': case 'actionButtonBeginning': case 'actionButtonBlank': case 'actionButtonDocument': case 'actionButtonEnd': case 'actionButtonForwardNext': case 'actionButtonHelp': case 'actionButtonHome': case 'actionButtonInformation': case 'actionButtonMovie': case 'actionButtonReturn': case 'actionButtonSound': case 'arc': case 'bevel': case 'blockArc': case 'borderCallout1': case 'borderCallout2': case 'borderCallout3': case 'bracePair': case 'bracketPair': case 'callout1': case 'callout2': case 'callout3': case 'can': case 'chartPlus': case 'chartStar': case 'chartX': case 'chevron': case 'chord': case 'cloud': case 'cloudCallout': case 'corner': case 'cornerTabs': case 'cube': case 'decagon': case 'diagStripe': case 'diamond': case 'dodecagon': case 'donut': case 'doubleWave': case 'downArrowCallout': case 'ellipseRibbon': case 'ellipseRibbon2': case 'flowChartAlternateProcess': case 'flowChartCollate': case 'flowChartConnector': case 'flowChartDecision': case 'flowChartDelay': case 'flowChartDisplay': case 'flowChartDocument': case 'flowChartExtract': case 'flowChartInputOutput': case 'flowChartInternalStorage': case 'flowChartMagneticDisk': case 'flowChartMagneticDrum': case 'flowChartMagneticTape': case 'flowChartManualInput': case 'flowChartManualOperation': case 'flowChartMerge': case 'flowChartMultidocument': case 'flowChartOfflineStorage': case 'flowChartOffpageConnector': case 'flowChartOnlineStorage': case 'flowChartOr': case 'flowChartPredefinedProcess': case 'flowChartPreparation': case 'flowChartProcess': case 'flowChartPunchedCard': case 'flowChartPunchedTape': case 'flowChartSort': case 'flowChartSummingJunction': case 'flowChartTerminator': case 'folderCorner': case 'frame': case 'funnel': case 'gear6': case 'gear9': case 'halfFrame': case 'heart': case 'heptagon': case 'hexagon': case 'homePlate': case 'horizontalScroll': case 'irregularSeal1': case 'irregularSeal2': case 'leftArrow': case 'leftArrowCallout': case 'leftBrace': case 'leftBracket': case 'leftRightArrowCallout': case 'leftRightRibbon': case 'irregularSeal1': case 'lightningBolt': case 'lineInv': case 'mathDivide': case 'mathEqual': case 'mathMinus': case 'mathMultiply': case 'mathNotEqual': case 'mathPlus': case 'moon': case 'nonIsoscelesTrapezoid': case 'noSmoking': case 'octagon': case 'parallelogram': case 'pentagon': case 'pie': case 'pieWedge': case 'plaque': case 'plaqueTabs': case 'plus': case 'quadArrowCallout': case 'rect': case 'ribbon': case 'ribbon2': case 'rightArrowCallout': case 'rightBrace': case 'rightBracket': case 'round1Rect': case 'round2DiagRect': case 'round2SameRect': case 'rtTriangle': case 'smileyFace': case 'snip1Rect': case 'snip2DiagRect': case 'snip2SameRect': case 'snipRoundRect': case 'squareTabs': case 'star10': case 'star12': case 'star16': case 'star24': case 'star32': case 'star4': case 'star5': case 'star6': case 'star7': case 'star8': case 'sun': case 'teardrop': case 'trapezoid': case 'upArrowCallout': case 'upDownArrowCallout': case 'verticalScroll': case 'wave': case 'wedgeEllipseCallout': case 'wedgeRectCallout': case 'wedgeRoundRectCallout': case 'rect': result += "<rect x='0' y='0' width='" + w + "' height='" + h + "' fill='" + fillColor + "' stroke='" + border.color + "' stroke-width='" + border.width + "' stroke-dasharray='" + border.strokeDasharray + "' />"; break; case 'ellipse': result += "<ellipse cx='" + w / 2 + "' cy='" + h / 2 + "' rx='" + w / 2 + "' ry='" + h / 2 + "' fill='" + fillColor + "' stroke='" + border.color + "' stroke-width='" + border.width + "' stroke-dasharray='" + border.strokeDasharray + "' />"; break; case 'roundRect': result += "<rect x='0' y='0' width='" + w + "' height='" + h + "' rx='7' ry='7' fill='" + fillColor + "' stroke='" + border.color + "' stroke-width='" + border.width + "' stroke-dasharray='" + border.strokeDasharray + "' />"; break; case 'bentConnector2': // 直角 (path) var d = ''; if (isFlipV) { d = 'M 0 ' + w + ' L ' + h + ' ' + w + ' L ' + h + ' 0'; } else { d = 'M ' + w + ' 0 L ' + w + ' ' + h + ' L 0 ' + h; } result += "<path d='" + d + "' stroke='" + border.color + "' stroke-width='" + border.width + "' stroke-dasharray='" + border.strokeDasharray + "' fill='none' "; if ( headEndNodeAttrs !== undefined && (headEndNodeAttrs['type'] === 'triangle' || headEndNodeAttrs['type'] === 'arrow') ) { result += "marker-start='url(#markerTriangle)' "; } if ( tailEndNodeAttrs !== undefined && (tailEndNodeAttrs['type'] === 'triangle' || tailEndNodeAttrs['type'] === 'arrow') ) { result += "marker-end='url(#markerTriangle)' "; } result += '/>'; break; case 'line': case 'straightConnector1': case 'bentConnector3': case 'bentConnector4': case 'bentConnector5': case 'curvedConnector2': case 'curvedConnector3': case 'curvedConnector4': case 'curvedConnector5': if (isFlipV) { result += "<line x1='" + w + "' y1='0' x2='0' y2='" + h + "' stroke='" + border.color + "' stroke-width='" + border.width + "' stroke-dasharray='" + border.strokeDasharray + "' "; } else { result += "<line x1='0' y1='0' x2='" + w + "' y2='" + h + "' stroke='" + border.color + "' stroke-width='" + border.width + "' stroke-dasharray='" + border.strokeDasharray + "' "; } if ( headEndNodeAttrs !== undefined && (headEndNodeAttrs['type'] === 'triangle' || headEndNodeAttrs['type'] === 'arrow') ) { result += "marker-start='url(#markerTriangle)' "; } if ( tailEndNodeAttrs !== undefined && (tailEndNodeAttrs['type'] === 'triangle' || tailEndNodeAttrs['type'] === 'arrow') ) { result += "marker-end='url(#markerTriangle)' "; } result += '/>'; break; case 'rightArrow': result += '<defs><marker id="markerTriangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="2.5" markerHeight="2.5" orient="auto-start-reverse" markerUnits="strokeWidth"><path d="M 0 0 L 10 5 L 0 10 z" /></marker></defs>'; result += "<line x1='0' y1='" + h / 2 + "' x2='" + (w - 15) + "' y2='" + h / 2 + "' stroke='" + border.color + "' stroke-width='" + h / 2 + "' stroke-dasharray='" + border.strokeDasharray + "' "; result += "marker-end='url(#markerTriangle)' />"; break; case 'downArrow': result += '<defs><marker id="markerTriangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="2.5" markerHeight="2.5" orient="auto-start-reverse" markerUnits="strokeWidth"><path d="M 0 0 L 10 5 L 0 10 z" /></marker></defs>'; result += "<line x1='" + w / 2 + "' y1='0' x2='" + w / 2 + "' y2='" + (h - 15) + "' stroke='" + border.color + "' stroke-width='" + w / 2 + "' stroke-dasharray='" + border.strokeDasharray + "' "; result += "marker-end='url(#markerTriangle)' />"; break; case 'bentArrow': case 'bentUpArrow': case 'stripedRightArrow': case 'quadArrow': case 'circularArrow': case 'swooshArrow': case 'leftRightArrow': case 'leftRightUpArrow': case 'leftUpArrow': case 'leftCircularArrow': case 'notchedRightArrow': case 'curvedDownArrow': case 'curvedLeftArrow': case 'curvedRightArrow': case 'curvedUpArrow': case 'upDownArrow': case 'upArrow': case 'uturnArrow': case 'leftRightCircularArrow': break; case 'triangle': break; case undefined: default: console.warn('Undefine shape type.'); } result += '</svg>'; result += "<div class='block content " + getVerticalAlign(node, slideLayoutSpNode, slideMasterSpNode, type) + "' _id='" + id + "' _idx='" + idx + "' _type='" + type + "' _name='" + name + "' style='" + getPosition(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode) + getSize(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode) + ' z-index: ' + order + ';' + "'>"; // TextBody if (node['p:txBody'] !== undefined) { result += genTextBody( node['p:txBody'], slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } result += '</div>'; } else { result += "<div class='block content " + getVerticalAlign(node, slideLayoutSpNode, slideMasterSpNode, type) + "' _id='" + id + "' _idx='" + idx + "' _type='" + type + "' _name='" + name + "' style='" + getPosition(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode) + getSize(slideXfrmNode, slideLayoutXfrmNode, slideMasterXfrmNode) + getBorder(node, false) + getShapeFill(node, false) + ' z-index: ' + order + ';' + "'>"; // TextBody if (node['p:txBody'] !== undefined) { result += genTextBody( node['p:txBody'], slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } result += '</div>'; } return result; } function getPosition(slideSpNode, slideLayoutSpNode, slideMasterSpNode) { var off = undefined; var x = -1, y = -1; if (slideSpNode !== undefined) { off = slideSpNode['a:off']['attrs']; } else if (slideLayoutSpNode !== undefined) { off = slideLayoutSpNode['a:off']['attrs']; } else if (slideMasterSpNode !== undefined) { off = slideMasterSpNode['a:off']['attrs']; } if (off === undefined) { return ''; } else { x = (parseInt(off['x']) * 96) / 914400; y = (parseInt(off['y']) * 96) / 914400; return isNaN(x) || isNaN(y) ? '' : 'top:' + y + 'px; left:' + x + 'px;'; } } function getSize(slideSpNode, slideLayoutSpNode, slideMasterSpNode) { var ext = undefined; var w = -1, h = -1; if (slideSpNode !== undefined) { ext = slideSpNode['a:ext']['attrs']; } else if (slideLayoutSpNode !== undefined) { ext = slideLayoutSpNode['a:ext']['attrs']; } else if (slideMasterSpNode !== undefined) { ext = slideMasterSpNode['a:ext']['attrs']; } if (ext === undefined) { return ''; } else { w = (parseInt(ext['cx']) * 96) / 914400; h = (parseInt(ext['cy']) * 96) / 914400; return isNaN(w) || isNaN(h) ? '' : 'width:' + w + 'px; height:' + h + 'px;'; } } function getHorizontalAlign( node, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, ) { var algn = getTextByPathList(node, ['a:pPr', 'attrs', 'algn']); if (algn === undefined) { algn = getTextByPathList(slideLayoutSpNode, [ 'p:txBody', 'a:p', 'a:pPr', 'attrs', 'algn', ]); if (algn === undefined) { algn = getTextByPathList(slideMasterSpNode, [ 'p:txBody', 'a:p', 'a:pPr', 'attrs', 'algn', ]); if (algn === undefined) { switch (type) { case 'title': case 'subTitle': case 'ctrTitle': algn = getTextByPathList(slideMasterTextStyles, [ 'p:titleStyle', 'a:lvl1pPr', 'attrs', 'alng', ]); break; default: algn = getTextByPathList(slideMasterTextStyles, [ 'p:otherStyle', 'a:lvl1pPr', 'attrs', 'alng', ]); } } } } // TODO: if (algn === undefined) { if (type == 'title' || type == 'subTitle' || type == 'ctrTitle') { return 'h-mid'; } else if (type == 'sldNum') { return 'h-right'; } } return algn === 'ctr' ? 'h-mid' : algn === 'r' ? 'h-right' : 'h-left'; } function getVerticalAlign( node, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, ) { // 上中下對齊: X, <a:bodyPr anchor="ctr">, <a:bodyPr anchor="b"> var anchor = getTextByPathList(node, [ 'p:txBody', 'a:bodyPr', 'attrs', 'anchor', ]); if (anchor === undefined) { anchor = getTextByPathList(slideLayoutSpNode, [ 'p:txBody', 'a:bodyPr', 'attrs', 'anchor', ]); if (anchor === undefined) { anchor = getTextByPathList(slideMasterSpNode, [ 'p:txBody', 'a:bodyPr', 'attrs', 'anchor', ]); } } return anchor === 'ctr' ? 'v-mid' : anchor === 'b' ? 'v-down' : 'v-up'; } function getFontType(node, type, slideMasterTextStyles) { var typeface = getTextByPathList(node, [ 'a:rPr', 'a:latin', 'attrs', 'typeface', ]); if (typeface === undefined) { var fontSchemeNode = getTextByPathList(themeContent, [ 'a:theme', 'a:themeElements', 'a:fontScheme', ]); if (type == 'title' || type == 'subTitle' || type == 'ctrTitle') { typeface = getTextByPathList(fontSchemeNode, [ 'a:majorFont', 'a:latin', 'attrs', 'typeface', ]); } else if (type == 'body') { typeface = getTextByPathList(fontSchemeNode, [ 'a:minorFont', 'a:latin', 'attrs', 'typeface', ]); } else { typeface = getTextByPathList(fontSchemeNode, [ 'a:minorFont', 'a:latin', 'attrs', 'typeface', ]); } } return typeface === undefined ? 'inherit' : typeface; } function getFontColor(node, type, slideMasterTextStyles) { var color = getTextByPathStr(node, 'a:rPr a:solidFill a:srgbClr attrs val'); return color === undefined ? '#000' : '#' + color; } function getFontSize( node, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, ) { var fontSize = undefined; if (node['a:rPr'] !== undefined) { fontSize = parseInt(node['a:rPr']['attrs']['sz']) / 100; } if (isNaN(fontSize) || fontSize === undefined) { var sz = getTextByPathList(slideLayoutSpNode, [ 'p:txBody', 'a:lstStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz', ]); fontSize = parseInt(sz) / 100; } if (isNaN(fontSize) || fontSize === undefined) { if (type == 'title' || type == 'subTitle' || type == 'ctrTitle') { var sz = getTextByPathList(slideMasterTextStyles, [ 'p:titleStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz', ]); } else if (type == 'body') { var sz = getTextByPathList(slideMasterTextStyles, [ 'p:bodyStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz', ]); } else if (type == 'dt' || type == 'sldNum') { var sz = '1200'; } else if (type === undefined) { var sz = getTextByPathList(slideMasterTextStyles, [ 'p:otherStyle', 'a:lvl1pPr', 'a:defRPr', 'attrs', 'sz', ]); } fontSize = parseInt(sz) / 100; } var baseline = getTextByPathList(node, ['a:rPr', 'attrs', 'baseline']); if (baseline !== undefined && !isNaN(fontSize)) { fontSize -= 10; } return isNaN(fontSize) ? 'inherit' : fontSize + 'pt'; } function getFontBold(node, type, slideMasterTextStyles) { return node['a:rPr'] !== undefined && node['a:rPr']['attrs']['b'] === '1' ? 'bold' : 'initial'; } function getFontItalic(node, type, slideMasterTextStyles) { return node['a:rPr'] !== undefined && node['a:rPr']['attrs']['i'] === '1' ? 'italic' : 'normal'; } function getFontDecoration(node, type, slideMasterTextStyles) { return node['a:rPr'] !== undefined && node['a:rPr']['attrs']['u'] === 'sng' ? 'underline' : 'initial'; } function getTextVerticalAlign(node, type, slideMasterTextStyles) { var baseline = getTextByPathList(node, ['a:rPr', 'attrs', 'baseline']); return baseline === undefined ? 'baseline' : parseInt(baseline) / 1000 + '%'; } function getBorder(node, isSvgMode) { var cssText = 'border: '; // 1. presentationML var lineNode = node['p:spPr']['a:ln']; // Border width: 1pt = 12700, default = 0.75pt var borderWidth = parseInt(getTextByPathList(lineNode, ['attrs', 'w'])) / 12700; if (isNaN(borderWidth) || borderWidth < 1) { cssText += '1pt '; } else { cssText += borderWidth + 'pt '; } // Border color var borderColor = getTextByPathList(lineNode, [ 'a:solidFill', 'a:srgbClr', 'attrs', 'val', ]); if (borderColor === undefined) { var schemeClrNode = getTextByPathList(lineNode, [ 'a:solidFill', 'a:schemeClr', ]); var schemeClr = 'a:' + getTextByPathList(schemeClrNode, ['attrs', 'val']); var borderColor = getSchemeColorFromTheme(schemeClr); } // 2. drawingML namespace if (borderColor === undefined) { var schemeClrNode = getTextByPathList(node, [ 'p:style', 'a:lnRef', 'a:schemeClr', ]); var schemeClr = 'a:' + getTextByPathList(schemeClrNode, ['attrs', 'val']); var borderColor = getSchemeColorFromTheme(schemeClr); if (borderColor !== undefined) { var shade = getTextByPathList(schemeClrNode, ['a:shade', 'attrs', 'val']); if (shade !== undefined) { shade = parseInt(shade) / 100000; var color = new colz.Color('#' + borderColor); color.setLum(color.hsl.l * shade); borderColor = color.hex.replace('#', ''); } } } if (borderColor === undefined) { if (isSvgMode) { borderColor = 'none'; } else { borderColor = '#000'; } } else { borderColor = '#' + borderColor; } cssText += ' ' + borderColor + ' '; // Border type var borderType = getTextByPathList(lineNode, ['a:prstDash', 'attrs', 'val']); var strokeDasharray = '0'; switch (borderType) { case 'solid': cssText += 'solid'; strokeDasharray = '0'; break; case 'dash': cssText += 'dashed'; strokeDasharray = '5'; break; case 'dashDot': cssText += 'dashed'; strokeDasharray = '5, 5, 1, 5'; break; case 'dot': cssText += 'dotted'; strokeDasharray = '1, 5'; break; case 'lgDash': cssText += 'dashed'; strokeDasharray = '10, 5'; break; case 'lgDashDotDot': cssText += 'dashed'; strokeDasharray = '10, 5, 1, 5, 1, 5'; break; case 'sysDash': cssText += 'dashed'; strokeDasharray = '5, 2'; break; case 'sysDashDot': cssText += 'dashed'; strokeDasharray = '5, 2, 1, 5'; break; case 'sysDashDotDot': cssText += 'dashed'; strokeDasharray = '5, 2, 1, 5, 1, 5'; break; case 'sysDot': cssText += 'dotted'; strokeDasharray = '2, 5'; break; case undefined: //console.log(borderType); default: //console.warn(borderType); //cssText += "#000 solid"; } if (isSvgMode) { return { color: borderColor, width: borderWidth, type: borderType, strokeDasharray: strokeDasharray, }; } else { return cssText + ';'; } } function getSlideBackgroundFill( slideContent, slideLayoutContent, slideMasterContent, ) { var bgColor = getSolidFill( getTextByPathList(slideContent, [ 'p:sld', 'p:cSld', 'p:bg', 'p:bgPr', 'a:solidFill', ]), ); if (bgColor === undefined) { bgColor = getSolidFill( getTextByPathList(slideLayoutContent, [ 'p:sldLayout', 'p:cSld', 'p:bg', 'p:bgPr', 'a:solidFill', ]), ); if (bgColor === undefined) { bgColor = getSolidFill( getTextByPathList(slideMasterContent, [ 'p:sldMaster', 'p:cSld', 'p:bg', 'p:bgPr', 'a:solidFill', ]), ); if (bgColor === undefined) { bgColor = 'FFF'; } } } return bgColor; } function getSchemeColorFromTheme(schemeClr) { // TODO: <p:clrMap ...> in slide master // e.g. tx2="dk2" bg2="lt2" tx1="dk1" bg1="lt1" switch (schemeClr) { case 'a:tx1': schemeClr = 'a:dk1'; break; case 'a:tx2': schemeClr = 'a:dk2'; break; case 'a:bg1': schemeClr = 'a:lt1'; break; case 'a:bg2': schemeClr = 'a:lt2'; break; } var refNode = getTextByPathList(themeContent, [ 'a:theme', 'a:themeElements', 'a:clrScheme', schemeClr, ]); var color = getTextByPathList(refNode, ['a:srgbClr', 'attrs', 'val']); if (color === undefined) { color = getTextByPathList(refNode, ['a:sysClr', 'attrs', 'lastClr']); } return color; } function getShapeFill(node, isSvgMode) { // 1. presentationML // p:spPr [a:noFill, solidFill, gradFill, blipFill, pattFill, grpFill] // From slide if (getTextByPathList(node, ['p:spPr', 'a:noFill']) !== undefined) { return isSvgMode ? 'none' : 'background-color: initial;'; } var fillColor = undefined; if (fillColor === undefined) { fillColor = getTextByPathList(node, [ 'p:spPr', 'a:solidFill', 'a:srgbClr', 'attrs', 'val', ]); } // From theme if (fillColor === undefined) { var schemeClr = 'a:' + getTextByPathList(node, [ 'p:spPr', 'a:solidFill', 'a:schemeClr', 'attrs', 'val', ]); fillColor = getSchemeColorFromTheme(schemeClr); } // 2. drawingML namespace if (fillColor === undefined) { var schemeClr = 'a:' + getTextByPathList(node, [ 'p:style', 'a:fillRef', 'a:schemeClr', 'attrs', 'val', ]); fillColor = getSchemeColorFromTheme(schemeClr); } if (fillColor !== undefined) { fillColor = '#' + fillColor; // Apply shade or tint // TODO: 較淺, 較深 80% var lumMod = parseInt( getTextByPathList(node, [ 'p:spPr', 'a:solidFill', 'a:schemeClr', 'a:lumMod', 'attrs', 'val', ]), ) / 100000; var lumOff = parseInt( getTextByPathList(node, [ 'p:spPr', 'a:solidFill', 'a:schemeClr', 'a:lumOff', 'attrs', 'val', ]), ) / 100000; if (isNaN(lumMod)) { lumMod = 1.0; } if (isNaN(lumOff)) { lumOff = 0; } //console.log([lumMod, lumOff]); fillColor = applyLumModify(fillColor, lumMod, lumOff); if (isSvgMode) { return fillColor; } else { return 'background-color: ' + fillColor + ';'; } } else { if (isSvgMode) { return 'none'; } else { return 'background-color: ' + fillColor + ';'; } } } function genTextBody( textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj, ) { var text = ''; var slideMasterTextStyles = warpObj['slideMasterTextStyles']; if (textBodyNode === undefined) { return text; } if (textBodyNode['a:p'].constructor === Array) { // multi p for (var i = 0; i < textBodyNode['a:p'].length; i++) { var pNode = textBodyNode['a:p'][i]; var rNode = pNode['a:r']; text += "<div class='" + getHorizontalAlign( pNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, ) + "'>"; text += genBuChar(pNode); if (rNode === undefined) { // without r text += genSpanElement( pNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } else if (rNode.constructor === Array) { // with multi r for (var j = 0; j < rNode.length; j++) { text += genSpanElement( rNode[j], slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } } else { // with one r text += genSpanElement( rNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } text += '</div>'; } } else { // one p var pNode = textBodyNode['a:p']; var rNode = pNode['a:r']; text += "<div class='" + getHorizontalAlign( pNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, ) + "'>"; text += genBuChar(pNode); if (rNode === undefined) { // without r text += genSpanElement( pNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } else if (rNode.constructor === Array) { // with multi r for (var j = 0; j < rNode.length; j++) { text += genSpanElement( rNode[j], slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } } else { // with one r text += genSpanElement( rNode, slideLayoutSpNode, slideMasterSpNode, type, warpObj, ); } text += '</div>'; } return text; } function genBuChar(node) { var pPrNode = node['a:pPr']; var lvl = parseInt(getTextByPathList(pPrNode, ['attrs', 'lvl'])); if (isNaN(lvl)) { lvl = 0; } var buChar = getTextByPathList(pPrNode, ['a:buChar', 'attrs', 'char']); if (buChar !== undefined) { var buFontAttrs = getTextByPathList(pPrNode, ['a:buFont', 'attrs']); if (buFontAttrs !== undefined) { var marginLeft = (parseInt(getTextByPathList(pPrNode, ['attrs', 'marL'])) * 96) / 914400; var marginRight = parseInt(buFontAttrs['pitchFamily']); if (isNaN(marginLeft)) { marginLeft = (328600 * 96) / 914400; } if (isNaN(marginRight)) { marginRight = 0; } var typeface = buFontAttrs['typeface']; return ( "<span style='font-family: " + typeface + '; margin-left: ' + marginLeft * lvl + 'px' + '; margin-right: ' + marginRight + 'px' + '; font-size: 20pt' + "'>" + buChar + '</span>' ); } else