diff --git a/lib/index.d.ts b/lib/index.d.ts
index 7ad0535..9dc32da 100644
--- a/lib/index.d.ts
+++ b/lib/index.d.ts
@@ -88,6 +88,9 @@ class XlsxTemplate
protected loadSheetRels(sheetFilename : string) : { rels : any};
protected loadDrawing(sheet : any, sheetFilename : string, rels : any) : { drawing : any};
protected writeDrawing(drawing : any);
+ protected initRichData() : void;
+ protected writeRichDataAlreadyExist(element : etree.ElementTree, elementSearchName : string, attributeName : string, attributeValue : string) : boolean;
+ protected writeRichData() : void;
protected moveAllImages(drawing : any, fromRow : number, nbRow : number);
protected loadTables(sheet : any, sheetFilename : any) : any;
protected writeTables(tables : any) : void;
@@ -97,6 +100,7 @@ class XlsxTemplate
protected substituteArray(cells : any[], cell : any, substitution : any);
protected substituteTable(row : any, newTableRows : any, cells : any[], cell : any, namedTables : any, substitution : any, key : any, placeholder : TemplatePlaceholder, drawing : etree.ElementTree) : any;
protected substituteImage(cell : any, string : string, placeholder: TemplatePlaceholder, substitution : any, drawing : etree.ElementTree) : boolean
+ protected substituteImageInCell(cell : any, substitution : any) : boolean;
protected cloneElement(element : any, deep? : any) : any;
protected replaceChildren(parent : any, children : any) : void;
protected getCurrentRow(row : any, rowsInserted : any) : number;
diff --git a/src/index.js b/src/index.js
index d7a28ea..26684af 100755
--- a/src/index.js
+++ b/src/index.js
@@ -321,6 +321,8 @@ class Workbook {
} else {
console.log("Need to implement initRels. Or init this with Excel");
}
+ } else if (placeholder.type === "imageincell" && placeholder.full) {
+ string = self.substituteImageInCell(cell, substitution);
} else {
if (placeholder.key) {
substitution = _get(substitutions, placeholder.name + '.' + placeholder.key);
@@ -439,6 +441,7 @@ class Workbook {
if (rels) {
self.archive.file(rels.filename, etree.tostring(rels.root));
}
+ self.writeRichData();
self.archive.file('[Content_Types].xml', etree.tostring(self.contentTypes));
// Remove calc chain - Excel will re-build, and we may have moved some formulae
if (self.calcChainPath && self.archive.file(self.calcChainPath)) {
@@ -1092,6 +1095,259 @@ class Workbook {
return newCellsInserted;
}
+
+ /**
+ * Init the RichData structure for ImageInCell
+ * There are 6 xml to init.
+ * If one of the files is available in the Excel archive, we read it rather than using the default value
+ */
+ initRichData() {
+
+ if (!this.richDataIsInit) {
+ const _relsrichValueRel = `
+
+ `;
+ const rdrichvalue = `
+
+ `;
+ const rdrichvaluestructure = `
+
+
+
+
+
+ `;
+ const rdRichValueTypes = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ const richValueRel = `
+
+ `;
+ const metadata = `
+
+
+
+
+
+
+
+
+ `;
+ const _relsrichValueRelFileName = 'xl/richData/_rels/richValueRel.xml.rels';
+ const rdrichvalueFileName = 'xl/richData/rdrichvalue.xml';
+ const rdrichvaluestructureFileName = 'xl/richData/rdrichvaluestructure.xml';
+ const rdRichValueTypesFileName = 'xl/richData/rdRichValueTypes.xml';
+ const richValueRelFileName = 'xl/richData/richValueRel.xml';
+ const metadataFileName = 'xl/metadata.xml';
+
+ this._relsrichValueRel = etree.parse(_relsrichValueRel).getroot();
+ this.rdrichvalue = etree.parse(rdrichvalue).getroot();
+ this.rdrichvaluestructure = etree.parse(rdrichvaluestructure).getroot();
+ this.rdRichValueTypes = etree.parse(rdRichValueTypes).getroot();
+ this.richValueRel = etree.parse(richValueRel).getroot();
+ this.metadata = etree.parse(metadata).getroot();
+ if(this.archive.file(_relsrichValueRelFileName) ){
+ this._relsrichValueRel = etree.parse(this.archive.file(_relsrichValueRelFileName).asText()).getroot()
+ }
+ if(this.archive.file(rdrichvalueFileName) ){
+ this.rdrichvalue = etree.parse(this.archive.file(rdrichvalueFileName).asText()).getroot()
+ }
+ if(this.archive.file(rdrichvaluestructureFileName) ){
+ this.rdrichvaluestructure = etree.parse(this.archive.file(rdrichvaluestructureFileName).asText()).getroot()
+ }
+ if(this.archive.file(rdRichValueTypesFileName) ){
+ this.rdRichValueTypes = etree.parse(this.archive.file(rdRichValueTypesFileName).asText()).getroot()
+ }
+ if(this.archive.file(richValueRelFileName) ){
+ this.richValueRel = etree.parse(this.archive.file(richValueRelFileName).asText()).getroot()
+ }
+ if(this.archive.file(metadataFileName) ){
+ this.metadata = etree.parse(this.archive.file(metadataFileName).asText()).getroot()
+ }
+ this.richDataIsInit = true;
+ }
+ };
+
+ writeRichDataAlreadyExist(element, elementSearchName, attributeName, attributeValue) {
+ for (const e of element.findall(elementSearchName)) {
+ if (e.attrib[attributeName] == attributeValue) {
+ return true;
+ }
+ };
+ return false;
+ };
+
+ /**
+ * Write the new RichData structure with the updated XML Value for each RichData files
+ */
+ writeRichData() {
+ if (this.richDataIsInit) {
+ const _relsrichValueRelFileName = 'xl/richData/_rels/richValueRel.xml.rels';
+ const rdrichvalueFileName = 'xl/richData/rdrichvalue.xml';
+ const rdrichvaluestructureFileName = 'xl/richData/rdrichvaluestructure.xml';
+ const rdRichValueTypesFileName = 'xl/richData/rdRichValueTypes.xml';
+ const richValueRelFileName = 'xl/richData/richValueRel.xml';
+ const metadataFileName = 'xl/metadata.xml';
+ this.archive.file(_relsrichValueRelFileName, etree.tostring(this._relsrichValueRel));
+ this.archive.file(rdrichvalueFileName, etree.tostring(this.rdrichvalue));
+ this.archive.file(rdrichvaluestructureFileName, etree.tostring(this.rdrichvaluestructure));
+ this.archive.file(rdRichValueTypesFileName, etree.tostring(this.rdRichValueTypes));
+ this.archive.file(richValueRelFileName, etree.tostring(this.richValueRel));
+ this.archive.file(metadataFileName, etree.tostring(this.metadata));
+
+ const wbrelsidMax = this.findMaxId(this.workbookRels, 'Relationship', 'Id', /rId(\d*)/);
+ if (!this.writeRichDataAlreadyExist(this.workbookRels, 'Relationship', 'Target', "richData/rdrichvaluestructure.xml")) {
+ var _rel = etree.SubElement(this.workbookRels, 'Relationship');
+ _rel.set('Id', 'rId' + wbrelsidMax);
+ _rel.set('Type', "http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueStructure");
+ _rel.set('Target', "richData/rdrichvaluestructure.xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.workbookRels, 'Relationship', 'Target', "richData/rdrichvalue.xml")) {
+ _rel = etree.SubElement(this.workbookRels, 'Relationship');
+ _rel.set('Id', `rId${wbrelsidMax + 1}`);
+ _rel.set('Type', "http://schemas.microsoft.com/office/2017/06/relationships/rdRichValue");
+ _rel.set('Target', "richData/rdrichvalue.xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.workbookRels, 'Relationship', 'Target', "richData/richValueRel.xml")) {
+ _rel = etree.SubElement(this.workbookRels, 'Relationship');
+ _rel.set('Id', `rId${wbrelsidMax + 2}`);
+ _rel.set('Type', "http://schemas.microsoft.com/office/2022/10/relationships/richValueRel");
+ _rel.set('Target', "richData/richValueRel.xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.workbookRels, 'Relationship', 'Target', "metadata.xml")) {
+ _rel = etree.SubElement(this.workbookRels, 'Relationship');
+ _rel.set('Id', `rId${wbrelsidMax + 3}`);
+ _rel.set('Type', "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata");
+ _rel.set('Target', "metadata.xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.workbookRels, 'Relationship', 'Target', "richData/rdRichValueTypes.xml")) {
+ _rel = etree.SubElement(this.workbookRels, 'Relationship');
+ _rel.set('Id', `rId${wbrelsidMax + 4}`);
+ _rel.set('Type', "http://schemas.microsoft.com/office/2017/06/relationships/rdRichValueTypes");
+ _rel.set('Target', "richData/rdRichValueTypes.xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.contentTypes, 'Override', 'PartName', "/xl/metadata.xml")) {
+ var ctOverride = etree.SubElement(this.contentTypes, 'Override');
+ ctOverride.set('PartName', "/xl/metadata.xml");
+ ctOverride.set('ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.contentTypes, 'Override', 'PartName', "/xl/richData/richValueRel.xml")) {
+ ctOverride = etree.SubElement(this.contentTypes, 'Override');
+ ctOverride.set('PartName', "/xl/richData/richValueRel.xml");
+ ctOverride.set('ContentType', "application/vnd.ms-excel.richvaluerel+xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.contentTypes, 'Override', 'PartName', "/xl/richData/rdrichvalue.xml")) {
+ ctOverride = etree.SubElement(this.contentTypes, 'Override');
+ ctOverride.set('PartName', "/xl/richData/rdrichvalue.xml");
+ ctOverride.set('ContentType', "application/vnd.ms-excel.rdrichvalue+xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.contentTypes, 'Override', 'PartName', "/xl/richData/rdrichvaluestructure.xml")) {
+ ctOverride = etree.SubElement(this.contentTypes, 'Override');
+ ctOverride.set('PartName', "/xl/richData/rdrichvaluestructure.xml");
+ ctOverride.set('ContentType', "application/vnd.ms-excel.rdrichvaluestructure+xml");
+ }
+ if (!this.writeRichDataAlreadyExist(this.contentTypes, 'Override', 'PartName', "/xl/richData/rdRichValueTypes.xml")) {
+ ctOverride = etree.SubElement(this.contentTypes, 'Override');
+ ctOverride.set('PartName', "/xl/richData/rdRichValueTypes.xml");
+ ctOverride.set('ContentType', "application/vnd.ms-excel.rdrichvaluetypes+xml");
+ }
+ this._rebuild()
+ }
+ }
+
+ substituteImageInCell(cell, substitution) {
+ if (substitution == null || substitution == "") {
+ this.insertCellValue(cell, "");
+ return true;
+ }
+ this.initRichData();
+ const maxFildId = this.findMaxFileId(/xl\/media\/image\d*.jpg/, /image(\d*)\.jpg/);
+ try {
+ substitution = this.imageToBuffer(substitution);
+ }
+ catch (error) {
+ if (this.option && this.option.handleImageError && typeof this.option.handleImageError === "function") {
+ this.option.handleImageError(substitution, error);
+ }
+ else {
+ throw error;
+ }
+ }
+ this.archive.file('xl/media/image' + maxFildId + '.jpg', this.toArrayBuffer(substitution), { binary: true, base64: false });
+ const maxIdRichData = this.findMaxId(this._relsrichValueRel, 'Relationship', 'Id', /rId(\d*)/);
+ const _rel = etree.SubElement(this._relsrichValueRel, 'Relationship');
+ _rel.set('Id', 'rId' + maxIdRichData);
+ _rel.set('Type', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image');
+ _rel.set('Target', '../media/image' + maxFildId + '.jpg');
+ const currentCountrdRichValue = this.rdrichvalue.get('count');
+ this.rdrichvalue.set('count', parseInt(currentCountrdRichValue) + 1);
+ const rv = etree.SubElement(this.rdrichvalue, 'rv');
+ rv.set('s', "0");
+ const firstV = etree.SubElement(rv, 'v');
+ const secondV = etree.SubElement(rv, 'v');
+ firstV.text = currentCountrdRichValue;
+ secondV.text = "5";
+ const rel = etree.SubElement(this.richValueRel, 'rel');
+ rel.set("r:id", 'rId' + maxIdRichData);
+ const futureMetadataCount = this.metadata.find('futureMetadata').get('count');
+ this.metadata.find('futureMetadata').set('count', parseInt(futureMetadataCount) + 1);
+ const bk = etree.SubElement(this.metadata.find('futureMetadata'), 'bk');
+ const extLst = etree.SubElement(bk, 'extLst');
+ const ext = etree.SubElement(extLst, 'ext');
+ ext.set("uri", "{3e2802c4-a4d2-4d8b-9148-e3be6c30e623}");
+ const xlrd_rvb = etree.SubElement(ext, 'xlrd:rvb');
+ xlrd_rvb.set("i", futureMetadataCount);
+ const valueMetadataCount = this.metadata.find('valueMetadata').get('count');
+ this.metadata.find('valueMetadata').set('count', parseInt(valueMetadataCount) + 1);
+ const bk_VM = etree.SubElement(this.metadata.find('valueMetadata'), 'bk');
+ const rc = etree.SubElement(bk_VM, 'rc');
+ rc.set("t", "1");
+ rc.set("v", valueMetadataCount);
+ cell.set("t", "e");
+ cell.set("vm", parseInt(currentCountrdRichValue) + 1);
+ this.insertCellValue(cell, "#VALUE!");
+ return true;
+ };
+
substituteImage(cell, string, placeholder, substitution, drawing) {
var self = this;
var self = this;
diff --git a/test/crud-test.ts b/test/crud-test.ts
index aacac31..419e72e 100644
--- a/test/crud-test.ts
+++ b/test/crud-test.ts
@@ -1150,6 +1150,41 @@ describe("CRUD operations", function() {
});
});
+ it("Insert imageincells and create rels", function(done) {
+ fs.readFile(path.join(__dirname, 'templates', 'test-insert-images_in_cell.xlsx'), function(err, data) {
+ expect(err).toBeNull();
+ var option = {
+ imageRootPath : path.join(__dirname, 'templates', 'dataset')
+ }
+ var t = new XlsxTemplate(data, option);
+ var imgB64 = 'iVBORw0KGgoAAAANSUhEUgAAALAAAAA2CAYAAABnXhObAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAAUjSURBVHhe7ZtbyGVjGMfXlmmccpqRcYgZmQsTMeVYQiJzozEYJRHCcCUaNy5kyg3KhUNEhjSRbwipIcoF0pRpxiFiLsYUIqcoZ8b2/6/1vKtnv3u9+/smuXjW/v/qv593PetZa+/17f9617vetb9BVVVDSIiQ7GFRiJC0PfBwOGRbiBAMBoPat+qBRWhkYBEaGViERgYWoZGBRWhkYBEaGViERgYWoZGBRWhkYBEaGViERgYWoZGBRWhkYBEaGViERgYWoenND9oHg8EFCOdBPJ57cDzfWf5MhLPZBr9AL2LdzmZxFNTui3AdtF+dqKqtqH3F2iOg9g6EVLcFdTPW7gT1CxAuhE6FFkG/Ql9Cm7HtC4gtqL0S4ehmaRzU32XNiWA/VyGcDGGT4c11sifg2Np/hWODB8iXsAJ3p2OBznL5rS5Pfey38wJPuzpqe6HuXFdDfdRVlwRo9r+stkvboYWu/ifLlzTP7z8XOBZ63mqTDuyqjap0XNMwhGCvStjjkeNw9q6ydgtyCxEub5Za5lnMWW0xsQzbn2btEZBfh0DtWSeq6h3oQeghaBMTYCl0UtMc4U/obegN6FXoJWgGXyBPhk7wfrcgfAJdXCemgNrJ3t0RBUo98KeW+wCiIdjmMCLfnpdYNrw+y+us9ltb/6FFisOWvO4Ut/4HaHWh5j7odJdLPfAXvnYuAk/Ztuuhn61NqQcOzt/QM02zWome6gBrJzj2Jey9imC7lQjsrcn1FsmlFj33WiS34Q+/0dotyL0L3QptttR/hT32cuzvWkQec6+ZNgNvaJo1ay3SlLyxOr5Zqm6wWKI1qpluW7NULcF+zrE29zkfId08sid/3Nq7BfazwMvSRfA+j0Lv2eIui71lqgyML/Z1xO+bxepqi+RGizTAW9Ycw0yZxr+8VJP7LZJLLJJjLBIOY2qwj1XQRtOM6VmIMxM5R0CcTWmFunRSzAX1wD0ifZnpMn4kzHCita+xyLEoKX3xNC9NTB7mCwz/ZL3U4A18sEWSThpyCMRenOL+qMsgfxNXD/IKTFqXox64RyRTcqossQ4mvsna5AmLacYinxv3sw9/YNvlFNpp/HoYlldY+2uLhLMMiTchvifFGYlJcJ6YJ0IrnDDcfq703sCkvpsDfAkrMNssxGsut8Ny1O8W2xkHQPOxsdPleOPGxmx6zG3Dyz4bfI9FKe/WP2DrqRUu/6PldnsWwgvwgU3av2YhguOHBX42IA0J/Fj2N4se3/tOwg8j0qwH3+POpjnC/z1G1RCipzxn0eMfBU8y8C70AINcyKeT4iAMIy6y9u3QN02zWoP8y9D50OHQMuTOaFaVQd0JuWxVJ1i/N7SUwqI/QY5CbjG0vy33hrorBmPddCSB2YYQm7L69y3ftW6L5eshBFhiy9R6X5sEOD+caja4PG8QeROX1pXUNYQoaX6qzQV4JcnrvTo/fzSl45nWHpj4YUT+Q5y8B+YPhRJ8nDsG/qjMf9UsVVdYZJ43hpxS4+NjPsHL4Xj8EdTxUXEi7adE/Q0WKD5mNno1rOClr7FzcxkMDS6P+zDiWNIsQg3yeyHHG6kRmGcsrfP50r5zZqvD+sUIh0L8ZdznqONj4zHSZ+ui6/N6sG2xY8K2/1gzNDjG2re9MrCYHpKBp3kIIXqADCxCIwOL0MjAIjQysAiNDCxCIwOL0MjAIjQysAiNDCxCIwOL0MjAIjQysAiNDCxCIwOL0MjAIjQysAhN+x8ZQkREPbAITFX9C5ozpqaetbGcAAAAAElFTkSuQmCC';
+
+ t.substitute('init_rels', {
+ imgB64 : imgB64,
+ });
+ var newData = t.generate();
+ var richDataFile = etree.parse(t.archive.file("xl/richData/_rels/richValueRel.xml.rels").asText()).getroot();
+ expect(richDataFile.findall("Relationship").length).toEqual(4);
+ var richDataFile = etree.parse(t.archive.file("xl/richData/rdrichvalue.xml").asText()).getroot();
+ expect(richDataFile.findall("rv").length).toEqual(4);
+ expect(parseInt(richDataFile.attrib.count)).toEqual(richDataFile.findall("rv").length);
+ var richDataFile = etree.parse(t.archive.file("xl/richData/richValueRel.xml").asText()).getroot();
+ expect(richDataFile.findall("rel").length).toEqual(4);
+ var richDataFile = etree.parse(t.archive.file("xl/metadata.xml").asText()).getroot();
+ expect(parseInt(richDataFile.find('futureMetadata').attrib.count)).toEqual(4);
+ expect(parseInt(richDataFile.find('valueMetadata').attrib.count)).toEqual(4);
+ expect(richDataFile.find('futureMetadata').findall("bk").length).toEqual(4);
+ expect(richDataFile.find('valueMetadata').findall("bk").length).toEqual(4);
+ var sheet1 = etree.parse(t.archive.file("xl/worksheets/sheet1.xml").asText()).getroot();
+ expect(sheet1.find("./sheetData/row[@r='3']/c[@r='B3']").attrib.vm).toEqual("1");
+ expect(sheet1.find("./sheetData/row[@r='5']/c[@r='K5']").attrib.vm).toEqual("2");
+ expect(sheet1.find("./sheetData/row[@r='6']/c[@r='D6']").attrib.vm).toEqual("3");
+ expect(sheet1.find("./sheetData/row[@r='10']/c[@r='H10']").attrib.vm).toEqual("4");
+ fs.writeFileSync('test/output/insert_imageincell.xlsx', newData, 'binary');
+ done();
+ });
+ });
+
it("Insert some format of image", function(done) {
fs.readFile(path.join(__dirname, "templates", "test-insert-images.xlsx"), function(err, data) {
expect(err).toBeNull();
diff --git a/test/templates/test-insert-images_in_cell.xlsx b/test/templates/test-insert-images_in_cell.xlsx
new file mode 100644
index 0000000..beb58cb
Binary files /dev/null and b/test/templates/test-insert-images_in_cell.xlsx differ