Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended POC for images. #84

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
148 changes: 134 additions & 14 deletions xlsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -2441,6 +2441,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) {
Expand Down Expand Up @@ -2482,6 +2484,48 @@ function write_ct(ct, opts) {
f3('themes');
['strs', 'styles'].forEach(f1);
['coreprops', 'extprops', 'custprops'].forEach(f3);

//TODO FIX THIS HACK
o[o.length] = '<Override PartName="/xl/drawings/drawing1.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing2.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing3.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing4.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing5.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing6.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing7.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing8.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing9.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing10.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing11.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing12.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing13.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing14.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing15.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing16.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing17.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing18.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing19.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing20.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing21.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing22.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing23.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing24.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing25.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing26.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing27.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing28.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing29.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing30.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing31.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing32.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing33.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing34.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing35.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing36.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing37.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing38.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing39.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
o[o.length] = '<Override PartName="/xl/drawings/drawing40.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>';
if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
return o.join("");
}
Expand Down Expand Up @@ -2517,7 +2561,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] === '<Relationship') {
if (y[0] === '<eelationship') {
var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
var canonictarget = y.TargetMode === 'External' ? y.Target : resolveRelativePathIntoAbsolute(y.Target);
rels[canonictarget] = rel;
Expand All @@ -2535,6 +2579,50 @@ 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];
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,
fromColOff = from.colOff || 0,
fromRowOff = from.rowOff || 0,
toColOff = to.colOff || 0,
toRowOff = to.rowOff || 99999;

var twoCell = '<xdr:from><xdr:col>'+fromCol+'</xdr:col><xdr:colOff>'+fromColOff+'</xdr:colOff><xdr:row>'+fromRow+'</xdr:row><xdr:rowOff>'+fromRowOff + '</xdr:rowOff></xdr:from>';
twoCell += '<xdr:to><xdr:col>' + toCol+ '</xdr:col><xdr:colOff>'+toColOff+'</xdr:colOff><xdr:row>'+toRow+'</xdr:row><xdr:rowOff>'+toRowOff+'</xdr:rowOff></xdr:to>';
twoCell += '<xdr:pic><xdr:nvPicPr><xdr:cNvPr id="'+(i+1)+'" name="'+image.name+'">';
twoCell += '</xdr:cNvPr><xdr:cNvPicPr><a:picLocks noChangeAspect="1"/></xdr:cNvPicPr></xdr:nvPicPr>';
twoCell += '<xdr:blipFill><a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="rId'+(i+1)+'">';
twoCell += '<a:extLst><a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}"><a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/></a:ext></a:extLst></a:blip>';
twoCell += '<a:stretch><a:fillRect/></a:stretch></xdr:blipFill><xdr:spPr>';
if(!skipXFrm){
twoCell += '<a:xfrm><a:off x="'+ image.spPr.xfrm.off.x + '" y= "'+ image.spPr.xfrm.off.y + '"/><a:ext cx="'+ image.spPr.xfrm.ext.cx+ '" cy="'+ image.spPr.xfrm.ext.cy + '"/></a:xfrm>';
}
twoCell += '<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr></xdr:pic><xdr:clientData/>';
o[o.length] = (writextag('xdr:twoCellAnchor', twoCell, images[i].attrs));
}
}

if(o.length>2){ o[o.length] = ('</xdr:wsDr>'); o[1]=o[1].replace("/>",">"); }
return o.join("");
}
/* TODO */
function write_rels(rels) {
var o = [];
Expand Down Expand Up @@ -4615,6 +4703,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) {
Expand Down Expand Up @@ -7864,19 +7953,31 @@ var parse_ws_xml_data = (function parse_ws_xml_data_factory() {
})();

function write_ws_xml_data(ws, opts, idx, wb) {
var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R, C;
for (C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for (R = range.s.r; R <= range.e.r; ++R) {
r = [];
rr = encode_row(R);
for (C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
if (ws[ref] === undefined) continue;
if ((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell);
var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R, C;
for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(R = range.s.r; R <= range.e.r; ++R) {
r = [];
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
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) {
// 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));
}
}
if (r.length > 0) o[o.length] = (writextag('row', r.join(""), {r: rr}));
}
return o.join("");
return o.join("");
}

var WS_XML_ROOT = writextag('worksheet', null, {
Expand All @@ -7885,6 +7986,7 @@ var WS_XML_ROOT = writextag('worksheet', null, {
});

function write_ws_xml(idx, opts, wb) {

var o = [XML_HEADER, WS_XML_ROOT];
var s = wb.SheetNames[idx], sidx = 0, rdata = "";
var ws = wb.Sheets[s];
Expand Down Expand Up @@ -7939,6 +8041,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] = '<drawing r:id="rId' + 1 + '"/>';

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']);
Expand Down Expand Up @@ -11725,6 +11829,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();
Expand Down Expand Up @@ -11772,6 +11879,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+1; ++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, 1, "../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);
Expand Down