From f5721e4027fe375b2ff35438df9121e5c9dd9e5c Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Tue, 29 Nov 2016 10:30:53 +0100 Subject: [PATCH 1/8] Implement POC for image embedding --- xlsx.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/xlsx.js b/xlsx.js index c29f5ceae..c07557b1d 100644 --- a/xlsx.js +++ b/xlsx.js @@ -2435,6 +2435,8 @@ var CTYPE_XML_ROOT = writextag('Types', null, { var CTYPE_DEFAULTS = [ ['xml', 'application/xml'], + ['png', 'image/png'], + ['jpg', 'image/jpeg'], ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'], ['rels', type2ct.rels[0]] ].map(function(x) { @@ -2476,6 +2478,7 @@ function write_ct(ct, opts) { f3('themes'); ['strs', 'styles'].forEach(f1); ['coreprops', 'extprops', 'custprops'].forEach(f3); + o[o.length] = ''; if(o.length>2){ o[o.length] = (''); o[1]=o[1].replace("/>",">"); } return o.join(""); } @@ -2529,6 +2532,39 @@ var RELS_ROOT = writextag('Relationships', null, { 'xmlns': XMLNS.RELS }); +var DRAW_ROOT = writextag('xdr:wsDr', null, { + 'xmlns:xdr': 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing', + 'xmlns:a': 'http://schemas.openxmlformats.org/drawingml/2006/main' + //'xmlns:ns0': XMLNS.RELS, + // 'xmlns': XMLNS.RELS +}); + +function write_drawing(images) { + var o = []; + o[o.length] = (XML_HEADER); + o[o.length] = (DRAW_ROOT); + + for (var i = 0; i < images.length; i++) { + var image = images[i]; + var pos = image.position || {}; + if (pos.type === 'twoCellAnchor') { + var from = pos.from || {}, to = pos.to || {}, + fromCol = from.col || 0, toCol = to.col || 0, + fromRow = from.row || 0, toRow = to.row || 0; + + var twoCell = ''+fromCol+'0'+fromRow+'0'; + twoCell += ''+toCol+'0'+toRow+'99999'; + twoCell += '' + twoCell += ''; + twoCell += ''; + twoCell += ''; + o[o.length] = (writextag('xdr:twoCellAnchor', twoCell, images[0].attrs)); + } + } + + if(o.length>2){ o[o.length] = (''); o[1]=o[1].replace("/>",">"); } + return o.join(""); +} /* TODO */ function write_rels(rels) { var o = []; @@ -7562,6 +7598,9 @@ function write_ws_xml(idx, opts, wb) { if(ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges'])); + var images = ws['!images'] || []; + if (images.length) o[o.length] = ''; + if(o.length>2) { o[o.length] = (''); o[1]=o[1].replace("/>",">"); } return o.join(""); } @@ -11277,6 +11316,9 @@ function add_rels(rels, rId, f, type, relobj) { rels[('/' + relobj.Target).replace("//","/")] = relobj; } +RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; +RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"; + function write_zip(wb, opts) { if(wb && !wb.SSF) { wb.SSF = SSF.get_table(); @@ -11324,6 +11366,19 @@ function write_zip(wb, opts) { add_rels(opts.rels, 1, f, RELS.WB); for(rId=1;rId <= wb.SheetNames.length; ++rId) { + var s = wb.SheetNames[rId-1], ws = wb.Sheets[s], + images = ws['!images'] || []; + var rels = ws['!rels'] = [], draw_rels = []; + for (var sId=1; sId <= images.length; ++sId) { + var image = images[sId - 1]; + f = 'xl/media/' + image.name; + zip.file(f, image.data, image.opts); + add_rels(draw_rels, sId, "../media/" + image.name, RELS.IMG); + } + zip.file("xl/drawings/drawing" + rId + "." + wbext, write_drawing(images)); + add_rels(rels, rId, "../drawings/drawing" + rId + "." + wbext, RELS.DRAW); + zip.file("xl/drawings/_rels/drawing" + rId + "." + wbext + ".rels", write_rels(draw_rels)); + zip.file("xl/worksheets/_rels/sheet" + rId + "." + wbext + '.rels', write_rels(rels)); f = "xl/worksheets/sheet" + rId + "." + wbext; zip.file(f, write_ws(rId-1, f, opts, wb)); ct.sheets.push(f); From 999b41df3a6b139478aeb6fe68f331c16ade081e Mon Sep 17 00:00:00 2001 From: Stewart Sims Date: Thu, 15 Dec 2016 13:21:42 +0000 Subject: [PATCH 2/8] fixing issues with multiple images, adding row height config and make keys method more defensive --- xlsx.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/xlsx.js b/xlsx.js index c07557b1d..8e1feb93b 100644 --- a/xlsx.js +++ b/xlsx.js @@ -1255,7 +1255,7 @@ return exports; if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; } function isval(x) { return x !== undefined && x !== null; } -function keys(o) { return Object.keys(o); } +function keys(o) { return o != null ? Object.keys(o) : []; } function evert_key(obj, key) { var o = [], K = keys(obj); @@ -2556,9 +2556,9 @@ function write_drawing(images) { twoCell += ''+toCol+'0'+toRow+'99999'; twoCell += '' twoCell += ''; - twoCell += ''; + twoCell += ''; twoCell += ''; - o[o.length] = (writextag('xdr:twoCellAnchor', twoCell, images[0].attrs)); + o[o.length] = (writextag('xdr:twoCellAnchor', twoCell, images[i].attrs)); } } @@ -4637,6 +4637,7 @@ function rgb_tint(hex, tint) { var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW; function width2px(width) { return (( width + ((128/MDW)|0)/256 )* MDW )|0; } function px2char(px) { return (((px - 5)/MDW * 100 + 0.5)|0)/100; } +function px2pt(px) { return px * 72 / 96; } function char2width(chr) { return (((chr * MDW + 5)/MDW*256)|0)/256; } function cycle_width(collw) { return char2width(px2char(width2px(collw))); } function find_mdw(collw, coll) { @@ -7570,8 +7571,20 @@ function write_ws_xml_data(ws, opts, idx, wb) { if(ws[ref] === undefined) continue; if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell); } - if(r.length > 0) o[o.length] = (writextag('row', r.join(""), {r:rr})); - } + if(r.length > 0) { + // 18.3.1.73 row + var params = {r:rr}; + if(typeof ws['!rows'] !== 'undefined' && ws['!rows'].length > R) { + var row = ws['!rows'][R]; + if (row.hidden) params.hidden = 1; + var height = -1; + if (row.hpx) height = px2pt(row.hpx); + else if (row.hpt) height = row.hpt; + if (height > -1) { params.ht = height; params.customHeight = 1; } + }; + o[o.length] = (writextag('row', r.join(""), params)); + } + } return o.join(""); } @@ -11369,7 +11382,7 @@ function write_zip(wb, opts) { var s = wb.SheetNames[rId-1], ws = wb.Sheets[s], images = ws['!images'] || []; var rels = ws['!rels'] = [], draw_rels = []; - for (var sId=1; sId <= images.length; ++sId) { + for (var sId=1; sId < images.length+1; ++sId) { var image = images[sId - 1]; f = 'xl/media/' + image.name; zip.file(f, image.data, image.opts); From 260dbe8835c01b77811c953db350693b716839a7 Mon Sep 17 00:00:00 2001 From: Geoff Golder Date: Fri, 18 Aug 2017 14:07:40 -0400 Subject: [PATCH 3/8] adding image capability upstream --- xlsx.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xlsx.js b/xlsx.js index fd997ea77..5c6926661 100644 --- a/xlsx.js +++ b/xlsx.js @@ -7989,6 +7989,8 @@ function write_ws_xml(idx, opts, wb) { } if (ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges'])); + var images = ws['!images'] || []; + if (images.length) o[o.length] = ''; if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup']); if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks']); From 71ef5ee85519e93d16feb0b588f55a9f550e8472 Mon Sep 17 00:00:00 2001 From: Geoff Golder Date: Fri, 25 Aug 2017 11:44:38 -0400 Subject: [PATCH 4/8] extending image functionality --- xlsx.js | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/xlsx.js b/xlsx.js index 5c6926661..abd6e8ade 100644 --- a/xlsx.js +++ b/xlsx.js @@ -2546,24 +2546,36 @@ var DRAW_ROOT = writextag('xdr:wsDr', null, { }); function write_drawing(images) { + console.log("entering write_drawing"); var o = []; o[o.length] = (XML_HEADER); o[o.length] = (DRAW_ROOT); for (var i = 0; i < images.length; i++) { var image = images[i]; + console.log("spr: ", image.spPr); var pos = image.position || {}; + var skipXFrm = !image.spPr; if (pos.type === 'twoCellAnchor') { var from = pos.from || {}, to = pos.to || {}, fromCol = from.col || 0, toCol = to.col || 0, - fromRow = from.row || 0, toRow = to.row || 0; - - var twoCell = ''+fromCol+'0'+fromRow+'0'; - twoCell += ''+toCol+'0'+toRow+'99999'; - twoCell += '' - twoCell += ''; - twoCell += ''; - twoCell += ''; + fromRow = from.row || 0, toRow = to.row || 0, + fromColOff = from.colOff || 0, + fromRowOff = from.rowOff || 0, + toColOff = to.colOff || 0, + toRowOff = to.rowOff || 99999; + + var twoCell = ''+fromCol+''+fromColOff+''+fromRow+''+fromRowOff + ''; + twoCell += '' + toCol+ ''+toColOff+''+toRow+''+toRowOff+''; + twoCell += ''; + twoCell += ''; + twoCell += ''; + twoCell += ''; + twoCell += ''; + if(!skipXFrm){ + twoCell += ''; + } + twoCell += ''; o[o.length] = (writextag('xdr:twoCellAnchor', twoCell, images[i].attrs)); } } @@ -7990,7 +8002,9 @@ function write_ws_xml(idx, opts, wb) { if (ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges'])); var images = ws['!images'] || []; - if (images.length) o[o.length] = ''; + for (var i = 1; i <= images.length; ++i){ + if (images.length) o[o.length] = ''; + } if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup']); if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks']); From 3f80b6cf484e24fce4e1e0c55db6830d5cabd874 Mon Sep 17 00:00:00 2001 From: Geoff Golder Date: Fri, 25 Aug 2017 11:45:51 -0400 Subject: [PATCH 5/8] remove consoles --- xlsx.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/xlsx.js b/xlsx.js index abd6e8ade..c8e8c197e 100644 --- a/xlsx.js +++ b/xlsx.js @@ -2546,14 +2546,12 @@ var DRAW_ROOT = writextag('xdr:wsDr', null, { }); function write_drawing(images) { - console.log("entering write_drawing"); var o = []; o[o.length] = (XML_HEADER); o[o.length] = (DRAW_ROOT); for (var i = 0; i < images.length; i++) { var image = images[i]; - console.log("spr: ", image.spPr); var pos = image.position || {}; var skipXFrm = !image.spPr; if (pos.type === 'twoCellAnchor') { From 52ab062b317a1c4e280b84535253347f5a860da0 Mon Sep 17 00:00:00 2001 From: Geoff Golder Date: Thu, 31 Aug 2017 17:26:10 -0400 Subject: [PATCH 6/8] adding support for multiple images --- xlsx.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xlsx.js b/xlsx.js index c8e8c197e..9497651db 100644 --- a/xlsx.js +++ b/xlsx.js @@ -2546,12 +2546,14 @@ var DRAW_ROOT = writextag('xdr:wsDr', null, { }); function write_drawing(images) { + console.log("entering write_drawing"); var o = []; o[o.length] = (XML_HEADER); o[o.length] = (DRAW_ROOT); for (var i = 0; i < images.length; i++) { var image = images[i]; + console.log("spr: ", image.spPr); var pos = image.position || {}; var skipXFrm = !image.spPr; if (pos.type === 'twoCellAnchor') { @@ -8000,9 +8002,7 @@ function write_ws_xml(idx, opts, wb) { if (ws['!merges'] !== undefined && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges'])); var images = ws['!images'] || []; - for (var i = 1; i <= images.length; ++i){ - if (images.length) o[o.length] = ''; - } + if (images.length) o[o.length] = ''; if (ws['!pageSetup'] !== undefined) o[o.length] = write_ws_xml_pagesetup(ws['!pageSetup']); if (ws['!rowBreaks'] !== undefined) o[o.length] = write_ws_xml_row_breaks(ws['!rowBreaks']); From ac2ada2d65e804e4fe7097344d5c5e56a127def6 Mon Sep 17 00:00:00 2001 From: Geoff Golder Date: Fri, 8 Sep 2017 12:16:20 -0400 Subject: [PATCH 7/8] add ability to have images on multiple tabs --- xlsx.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/xlsx.js b/xlsx.js index 9497651db..434b6e657 100644 --- a/xlsx.js +++ b/xlsx.js @@ -2484,7 +2484,17 @@ function write_ct(ct, opts) { f3('themes'); ['strs', 'styles'].forEach(f1); ['coreprops', 'extprops', 'custprops'].forEach(f3); + + //TODO FIX THIS HACK o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; if(o.length>2){ o[o.length] = (''); o[1]=o[1].replace("/>",">"); } return o.join(""); } @@ -2520,7 +2530,7 @@ function parse_rels(data, currentFilePath) { data.match(tagregex).forEach(function(x) { var y = parsexmltag(x); /* 9.3.2.2 OPC_Relationships */ - if (y[0] === ' Date: Tue, 19 Sep 2017 14:59:13 -0400 Subject: [PATCH 8/8] more sheets for images --- xlsx.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/xlsx.js b/xlsx.js index 434b6e657..ac0fe07e2 100644 --- a/xlsx.js +++ b/xlsx.js @@ -2495,6 +2495,37 @@ function write_ct(ct, opts) { o[o.length] = ''; o[o.length] = ''; o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; + o[o.length] = ''; if(o.length>2){ o[o.length] = (''); o[1]=o[1].replace("/>",">"); } return o.join(""); }