UNPKG

spider-officegen

Version:

Office Open XML Generator using Node.js streams. Supporting Microsoft Office 2007 and later Word (docx), PowerPoint (pptx,ppsx) and Excel (xlsx). This module is for all frameworks and environments. No need for any commandline tool - this module is doing e

739 lines (673 loc) 24.6 kB
var fast_image_size = require('fast-image-size'); module.exports = { // assume passed in an array of row objects getTable: function (rows, tblOpts, gen_private) { tblOpts = tblOpts || {}; this.gen_private = gen_private; var self = this; return self._getBase( rows.map(function (row) { return self._getRow( row.map(function (cell) { cell = cell || {}; if (typeof cell === 'string' || typeof cell === 'number') { var val = cell; cell = { val: val }; } return self._getCell(cell.val, cell.opts, tblOpts); }), tblOpts ); }), self._getColSpecs(rows, tblOpts), tblOpts ); }, _getBase: function (rowSpecs, colSpecs, opts) { var self = this; var baseTable = { "w:tbl": { "w:tblPr": { "w:tblStyle": { "@w:val": "a3" }, "w:tblW": { "@w:w": "0", "@w:type": "auto" }, "w:tblLook": { "@w:val": "04A0", "@w:firstRow": "1", "@w:lastRow": "0", "@w:firstColumn": "1", "@w:lastColumn": "0", "@w:noHBand": "0", "@w:noVBand": "1" } }, "w:tblGrid": { "#list": colSpecs }, "#list": [rowSpecs] } }; var borders = {}; if (opts.borders) { borders = { "w:top": { "@w:val": "single", "@w:sz": opts.borderSize, "@w:space": "0", "@w:color": opts.borderColor }, "w:start": { "@w:val": "single", "@w:sz": opts.borderSize, "@w:space": "0", "@w:color": opts.borderColor }, "w:bottom": { "@w:val": "single", "@w:sz": opts.borderSize, "@w:space": "0", "@w:color": opts.borderColor }, "w:end": { "@w:val": "single", "@w:sz": opts.borderSize, "@w:space": "0", "@w:color": opts.borderColor }, "w:insideH": { "@w:val": "single", "@w:sz": opts.bordersInsideH ? opts.borderSize : 0, "@w:space": "0", "@w:color": opts.bordersInsideH ? opts.borderColor : 'ffffff' }, } if (opts.bordersInsideV) { borders["w:insideV"] = { "@w:val": "single", "@w:sz": opts.bordersInsideV ? opts.borderSize : 0, "@w:space": "0", "@w:color": opts.bordersInsideV ? opts.borderColor : 'ffffff' } } } if (opts.borders) { baseTable["w:tbl"]["w:tblPr"]["w:tblBorders"] = borders; } return baseTable; }, _getColSpecs: function (cols, opts) { var self = this; return cols[0].map(function (val, idx) { return self._tblGrid(opts); }); }, // TODO _tblGrid: function (opts) { return { "w:gridCol": { "@w:w": opts.tableColWidth || "1" } }; }, _getRow: function (cells, opts) { return { "w:tr": { "@w:rsidR": "00995B51", "@w:rsidTr": "007F1D13", "#list": [cells] // populate this with an array of table cell objects } }; }, _getCell: function (val, opts, tblOpts) { opts = opts || {}; // var b = {}; var content = [{ "w:p": { "@w:rsidR": "00995B51", "@w:rsidRPr": "00722E63", "@w:rsidRDefault": "00995B51", "w:pPr": { "w:jc": { "@w:val": opts.align || tblOpts.tableAlign || "center" }, "w:spacing": { "@w:before": opts.paddingTop || "120", "@w:after": opts.paddingBottom || "60", "@w:line": opts.lineHeight || "276", "@w:lineRule": opts.lineRule || "auto", }, }, "w:r": { "@w:rsidRPr": "00722E63", "w:rPr": { "w:rFonts": { "@w:ascii": opts.fontFamily || tblOpts.tableFontFamily || "宋体", "@w:hAnsi": opts.fontFamily || tblOpts.tableFontFamily || "宋体" }, "w:color": { "@w:val": opts.color || tblOpts.tableColor || "000" }, "w:b": {}, "w:sz": { "@w:val": opts.sz || tblOpts.sz || "24" }, "w:szCs": { "@w:val": opts.sz || tblOpts.sz || "24" }, }, "w:t": val } } }] if (typeof val != 'string' && typeof val != 'number') { if (Array.isArray(val)) { content = this._getComplexCell(val, tblOpts); } } else { if (!opts.b) { delete content[0]["w:p"]["w:r"]["w:rPr"]["w:b"]; } } var cellObj = { "w:tc": { "w:tcPr": { "w:tcW": { "@w:w": opts.cellColWidth || tblOpts.tableColWidth || "0", "@w:type": "dxa" }, "w:shd": { "@w:val": "clear", "@w:color": "auto", "@w:fill": opts.shd && opts.shd.fill || "", "@w:themeFill": opts.shd && opts.shd.themeFill || "", "@w:themeFillTint": opts.shd && opts.shd.themeFillTint || "" } }, "#list": [content] } } if (opts.gridSpan) { cellObj["w:tc"]["w:tcPr"]["w:gridSpan"] = { "@w:val": opts.gridSpan }; } if (opts.vAlign) { cellObj["w:tc"]["w:tcPr"]["w:vAlign"] = { "@w:val": opts.vAlign }; } var cellBorders = {}; function parseBorder(border) { if (border) { return { "@w:color": border.color || "auto", "@w:space": border.space || "0", "@w:sz": border.sz || "4", "@w:val": border.val || "single" }; } return null; } if (opts.borders) { if (opts.borders.left) { cellBorders["w:left"] = parseBorder(opts.borders.left); } if (opts.borders.right) { cellBorders["w:right"] = parseBorder(opts.borders.right); } if (opts.borders.top) { cellBorders["w:top"] = parseBorder(opts.borders.top); } if (opts.borders.bottom) { cellBorders["w:bottom"] = parseBorder(opts.borders.bottom); } } if (Object.keys(cellBorders).length > 0) { cellObj["w:tc"]["w:tcPr"]["w:tcBorders"] = cellBorders; } return cellObj; }, _getComplexCell: function (cellVal, tblOpts) { var _this = this; var content = cellVal.map(function (cell) { /* * TODO: add more options. like adding tables , pictures etc */ var rowObject = []; if (cell.type === 'text' || cell.type === 'number') { var opts = cell.opts || {}; if (cell.inline) { cell.values.forEach(function (row) { var tempRow = { "w:r": { "@w:rsidRPr": "00722E63", "w:rPr": { "w:rFonts": { "@w:ascii": row.opts.fontFamily || tblOpts.tableFontFamily || "宋体", "@w:hAnsi": row.opts.fontFamily || tblOpts.tableFontFamily || "宋体" }, "w:color": { "@w:val": row.opts.color || tblOpts.tableColor || "000" }, "w:b": {}, "w:sz": { "@w:val": row.opts.sz || tblOpts.sz || "16" }, "w:szCs": { "@w:val": row.opts.sz || tblOpts.sz || "16" } }, "w:t": row.val } } if (!row.opts.b) { delete tempRow["w:r"]["w:rPr"]["w:b"]; } rowObject.push(tempRow); }) } else { tempRow = { "w:r": { "@w:rsidRPr": "00722E63", "w:rPr": { "w:rFonts": { "@w:ascii": opts.fontFamily || tblOpts.tableFontFamily || "宋体", "@w:hAnsi": opts.fontFamily || tblOpts.tableFontFamily || "宋体" }, "w:color": { "@w:val": opts.color || tblOpts.tableColor || "000" }, "w:b": {}, "w:sz": { "@w:val": opts.sz || tblOpts.sz || "16" }, "w:szCs": { "@w:val": opts.sz || tblOpts.sz || "16" } }, "w:t": cell.val } } if (!opts.b) { delete tempRow["w:r"]["w:rPr"]["w:b"]; } rowObject.push(tempRow); } return [ { "w:p": { "@w:rsidR": "00995B51", "@w:rsidRPr": "00722E63", "@w:rsidRDefault": "00995B51", "w:pPr": { "w:jc": { "@w:val": opts.align || tblOpts.tableAlign || "center" }, "w:spacing": { "@w:before": opts.paddingTop || "120", "@w:after": opts.paddingBottom || "60", }, }, "#list": [rowObject] } }]; } if (cell.type === 'image') { var image = _this._insertImage(cell.path, cell.opts, cell.type); var img = { "wp:inline": { "@distT": "0", "@distB": "0", "@distL": "0", "@distR": "0", "wp:extent": { "@cx": (image.options.cx * Math.floor(12573.739)), "@cy": (image.options.cy * Math.floor(12573.739)) }, "wp:effectExtent": { "@l": "0", "@t": "0", "@r": "0", "@b": "0" }, "wp:docPr": { "@id": "1", "@name": "Picture 0", "@descr": "Picture 0" }, "wp:cNvGraphicFramePr": { "a:graphicFrameLocks": { "@xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "@noChangeAspect": "1" } }, "a:graphic": { "@xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "a:graphicData": { "@uri": "http://schemas.openxmlformats.org/drawingml/2006/picture", "pic:pic": { "@xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture", "pic:nvPicPr": { "pic:cNvPr": { "@id": image.image_id, "@name": "Picture 0" }, "pic:cNvPicPr": {} }, "pic:blipFill": { "a:blip": { "@r:embed": "rId" + image.rel_id, "@cstate": "print" }, "a:stretch": { "a:fillRect": {} } }, "pic:spPr": { "a:xfrm": { "a:off": { "@x": "0", "@y": "0" }, "a:ext": { "@cx": (image.options.cx * Math.floor(12573.739)), "@cy": (image.options.cy * Math.floor(12573.739)) } }, "a:prstGeom": { "@prst": "rect", "a:avLst": {} } } } } } } } if (cell.opts.anchoredImage) { img = { "wp:anchor": { "@allowOverlap": "1", "@behindDoc": "1", "@distB": "0", "@distL": "0", "@distR": "0", "@distT": "10000", "@layoutInCell": "1", "@locked": "0", "@relativeHeight": "251656192", "@simplePos": "0", "wp:simplePos": { "@x": "0", "@y": "0" }, "wp:positionH": { "@relativeFrom": "page", "wp:posOffset": image.options.offsetH || "191106" }, "wp:positionV": { "@relativeFrom": "page", "wp:posOffset": image.options.offsetV || "240503" }, "wp:extent": { "@cx": (image.options.cx * Math.floor(12573.739)), "@cy": (image.options.cy * Math.floor(12573.739)) }, "wp:effectExtent": { "@l": "0", "@t": "0", "@r": "0", "@b": "0" }, "wp:wrapNone": {}, "wp:docPr": { "@id": "1", "@name": "Picture 0", "@descr": "Picture 0" }, "wp:cNvGraphicFramePr": { "a:graphicFrameLocks": { "@xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "@noChangeAspect": "1" } }, "a:graphic": { "@xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "a:graphicData": { "@uri": "http://schemas.openxmlformats.org/drawingml/2006/picture", "pic:pic": { "@xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture", "pic:nvPicPr": { "pic:cNvPr": { "@id": image.image_id, "@name": "Picture 0" }, "pic:cNvPicPr": {} }, "pic:blipFill": { "a:blip": { "@r:embed": "rId" + image.rel_id, "@cstate": "print" }, "a:stretch": { "a:fillRect": {} } }, "pic:spPr": { "a:xfrm": { "a:off": { "@x": "0", "@y": "0" }, "a:ext": { "@cx": (image.options.cx * Math.floor(12573.739)), "@cy": (image.options.cy * Math.floor(12573.739)) } }, "a:prstGeom": { "@prst": "rect", "a:avLst": {} } } } } } } } } let cellText = ""; if (cell.text) { //if we have a text inline with the image add a space between the image & the text if (cell.opts.textAfterImage) { cellText = cell.text + " "; } else { cellText = " " + cell.text; } } var ret = [ { "w:p": { "w:pPr": { "w:jc": { "@w:val": cell.opts.align || "center" }, "w:spacing": { // add some padding above and below so the image doesn't overlap the borders of the table "@w:before": cell.opts.paddingTop || "100", "@w:after": cell.opts.paddingBottom || "60", "@w:line": cell.opts.lineHeight || "276", "@w:lineRule": cell.opts.lineRule || "auto", } }, "w:tcPr": { "w:vAlign": { "@w:val": cell.opts.vAlign || "center" } }, "w:r": { "@w:rsidRPr": "00722E63", "w:rPr": { "w:rFonts": { "@w:ascii": cell.opts.fontFamily || "Avenir Book", "@w:hAnsi": cell.opts.fontFamily || "Avenir Book" }, "w:color": { "@w:val": cell.opts.color || "000" }, "w:b": {}, "w:sz": { "@w:val": cell.opts.sz || "16" }, "w:szCs": { "@w:val": cell.opts.sz || "16" } }, } } } ]; if (!cell.opts.b) { delete ret[0]["w:p"]["w:r"]["w:rPr"]["w:b"]; } if (cell.opts.textAfterImage) { ret[0]["w:p"]["w:r"]["w:t"] = { "@xml:space": "preserve", // we must have a space between the image and the text "#text": cellText, // check xmlbuilder doc to see how to add text nodes }; ret[0]["w:p"]["w:r"]["w:drawing"] = img; } else { ret[0]["w:p"]["w:r"]["w:drawing"] = img; ret[0]["w:p"]["w:r"]["w:t"] = { "@xml:space": "preserve", // we must have a space between the image and the text "#text": cellText, // check xmlbuilder doc to see how to add text nodes }; } return ret; } if (!cell.type && cell.inline) { var opts = cell.opts || {}; cell.values.forEach(function (row) { var tempRow = {}; if (row.type && (row.type === 'text' || row.type === 'number')) { tempRow = { "w:r": { "@w:rsidRPr": "00722E63", "w:rPr": { "w:rFonts": { "@w:ascii": row.opts.fontFamily || tblOpts.tableFontFamily || "宋体", "@w:hAnsi": row.opts.fontFamily || tblOpts.tableFontFamily || "宋体" }, "w:color": { "@w:val": row.opts.color || tblOpts.tableColor || "000" }, "w:b": {}, "w:sz": { "@w:val": row.opts.sz || tblOpts.sz || "16" }, "w:szCs": { "@w:val": row.opts.sz || tblOpts.sz || "16" } }, "w:t": row.val } } if (!row.opts.b) { delete tempRow["w:r"]["w:rPr"]["w:b"]; } } if (row.type && row.type === 'image') { var image = _this._insertImage(row.path, row.opts, row.type); var img = { "wp:inline": { "@distT": "0", "@distB": "0", "@distL": "0", "@distR": "0", "wp:extent": { "@cx": (image.options.cx * Math.floor(12573.739)), "@cy": (image.options.cx * Math.floor(12573.739)) }, "wp:effectExtent": { "@l": "19050", "@t": "0", "@r": "9525", "@b": "0" }, "wp:docPr": { "@id": "1", "@name": "Picture 0", "@descr": "Picture 0" }, "wp:cNvGraphicFramePr": { "a:graphicFrameLocks": { "@xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "@noChangeAspect": "1" } }, "a:graphic": { "@xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "a:graphicData": { "@uri": "http://schemas.openxmlformats.org/drawingml/2006/picture", "pic:pic": { "@xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture", "pic:nvPicPr": { "pic:cNvPr": { "@id": image.image_id, "@name": "Picture 0" }, "pic:cNvPicPr": {} }, "pic:blipFill": { "a:blip": { "@r:embed": "rId" + image.rel_id, "@cstate": "print" }, "a:stretch": { "a:fillRect": {} } }, "pic:spPr": { "a:xfrm": { "a:off": { "@x": "0", "@y": "0" }, "a:ext": { "@cx": (image.options.cx * Math.floor(12573.739)), "@cy": (image.options.cx * Math.floor(12573.739)) } }, "a:prstGeom": { "@prst": "rect", "a:avLst": {} } } } } } } } tempRow = { "w:r": { "@w:rsidRPr": "00722E63", "w:rPr": { "w:rFonts": { "@w:ascii": "宋体", "@w:hAnsi": "宋体" } }, "w:drawing": img } } } if (row.type && row.type === 'lineBreak') { tempRow = { "w:r": { "w:br": {} } } } rowObject.push(tempRow); }) return [ { "w:p": { "@w:rsidR": "00995B51", "@w:rsidRPr": "00722E63", "@w:rsidRDefault": "00995B51", "w:pPr": { "w:jc": { "@w:val": opts.align || tblOpts.tableAlign || "center" }, }, "#list": [rowObject] } }]; } }) return content; }, _insertImage: function (image_path, opt, image_format_type) { var image_type = (typeof image_format_type == 'string') ? image_format_type : 'png'; var defWidth = 320; var defHeight = 200; if (typeof image_path == 'string') { var ret_data = fast_image_size(image_path); if (ret_data.type == 'unknown') { var image_ext = path.extname(image_path); switch (image_ext) { case '.bmp': image_type = 'bmp'; break; case '.gif': image_type = 'gif'; break; case '.jpg': case '.jpeg': image_type = 'jpeg'; break; case '.emf': image_type = 'emf'; break; case '.tiff': image_type = 'tiff'; break; } // End of switch. } else { if (ret_data.width) { defWidth = ret_data.width; } // Endif. if (ret_data.height) { defHeight = ret_data.height; } // Endif. image_type = ret_data.type; if (image_type == 'jpg') { image_type = 'jpeg'; } // Endif. } // Endif. } // Endif. var imgObj = { image: image_path, options: opt || {} }; if (!imgObj.options.cx && defWidth) { imgObj.options.cx = defWidth; } // Endif. if (!imgObj.options.cy && defHeight) { imgObj.options.cy = defHeight; } // Endif. var image_id = this.gen_private.type.msoffice.src_files_list.indexOf(image_path); var image_rel_id = -1; if (image_id >= 0) { for (var j = 0, total_size_j = this.gen_private.type.msoffice.rels_app.length; j < total_size_j; j++) { if (this.gen_private.type.msoffice.rels_app[j].target == ('media/image' + (image_id + 1) + '.' + image_type)) { image_rel_id = j + 1; } // Endif. } // Endif. } else { image_id = this.gen_private.type.msoffice.src_files_list.length; this.gen_private.type.msoffice.src_files_list[image_id] = image_path; this.gen_private.plugs.intAddAnyResourceToParse('word\\media\\image' + (image_id + 1) + '.' + image_type, (typeof image_path == 'string') ? 'file' : 'stream', image_path, null, false); } // Endif. if (image_rel_id == -1) { image_rel_id = this.gen_private.type.msoffice.rels_app.length + 1; this.gen_private.type.msoffice.rels_app.push( { type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', target: 'media/image' + (image_id + 1) + '.' + image_type, clear: 'data' } ); } // Endif. if ((opt || {}).link) { var link_rel_id = this.gen_private.type.msoffice.rels_app.length + 1; this.gen_private.type.msoffice.rels_app.push({ type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', target: opt.link, targetMode: 'External' }); imgObj.link_rel_id = link_rel_id; } // Endif. imgObj.image_id = image_id; imgObj.rel_id = image_rel_id; return imgObj; } };