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

Add URL Image Support #133

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Ola-Alkhateeb
Copy link

@Ola-Alkhateeb Ola-Alkhateeb commented Feb 2, 2021

Added URL Image support ,
what i did basically is converting urls into base64 then the whole process works just fine , this is an async process so i had to change loops and functions calls using async/await method

Please Note that in index.js file this line is written in typescript ' import zip from "jszip" so i had to replace it in js '
And i added this library to the url convert 'image-to-base64'

Copy link
Collaborator

@kant2002 kant2002 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree with direction of changes and functionality. But as it is it is cannot be accepted. For example change functions from sync to async is a breaking change for user. I would like to introduce new functions for that which perform async operation.

Also please leave whitespace changes outside of PR. if you want fix formatting, please do that in separate PR so we can discuss them separately.


// Perform a table substitution. May update `newTableRows` and `cells` and change `cell`.
// Returns total number of new cells inserted on the original row.
Workbook.prototype.substituteTable = function(row, newTableRows, cells, cell, namedTables, substitution, key, placeholder, drawing) {
Workbook.prototype.substituteTable = async function(row, newTableRows, cells, cell, namedTables, substitution, key, placeholder, drawing) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is breaking change for consumers.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree it's a breaking change , so you will need to upgrade library version, instead of creating new functions behaves exactly the same

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not this this addition is that critical, so all customers of this library should asyncify their code. For some of them this maybe a disruptive change. I prefer to have additional functions which handle async cases. Both of sync/async versions can share a lot internally.

@@ -561,20 +565,20 @@ module.exports = (function() {
return rels;
}
//Load Drawing file
Workbook.prototype.loadDrawing = function (sheet, sheetFilename, rels) {
Workbook.prototype.loadDrawing = async function (sheet, sheetFilename, rels) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is breaking change for consumers.

@morrislaw715
Copy link

morrislaw715 commented Oct 4, 2023

May I know any update about imageURL? Is it available to use barcode api url?
Example:
excel: ${Sheet1[0].qr_code}
json: {qr_code:http://192.168.1.2:10/data=helloworld}

@morrislaw715
Copy link

Finally, I copy 'substituteImage' to new function called 'substituteImgurl'.
and add-on one more placeholder.
Then I parse the image to buffer directly in backend.

excel template:
image
result:
image

add-on this in function 'substitute'

 } else if (placeholder.type === "imgurl" && placeholder.full) {
      if (rels != null) {
          if (drawing == null) {
              drawing = self.loadDrawing(sheet.root, sheet.filename, rels.root);
          }
          string = self.substituteImgurl(cell, string, placeholder, substitution, drawing);
      } else {
          console.log("Need to implement initRels. Or init this with Excel");
      }
  }

Mainly modified for 'substituteImgurl' in order to directly put the buffer into 'substitutions'
substitution = self.imageToBuffer(substitution[placeholder.key]);

add-on 'substituteImgurl'

substituteImgurl(cell, string, placeholder, substitution, drawing) {
    var self = this;
    self.substituteScalar(cell, string, placeholder, '');
    if (substitution == null || substitution == "") {
        return true;
    }
    // get max refid
    // update rel file.
    var maxId = self.findMaxId(drawing.relRoot, 'Relationship', 'Id', /rId(\d*)/);
    var maxFildId = self.findMaxFileId(/xl\/media\/image\d*.jpg/, /image(\d*)\.jpg/);
    var rel = etree.SubElement(drawing.relRoot, 'Relationship');
    rel.set('Id', 'rId' + maxId);
    rel.set('Type', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image');

    rel.set('Target', '../media/image' + maxFildId + '.jpg');
    function toArrayBuffer(buffer) {
        var ab = new ArrayBuffer(buffer.length);
        var view = new Uint8Array(ab);
        for (var i = 0; i < buffer.length; ++i) {
            view[i] = buffer[i];
        }
        return ab;
    };
    try {
        substitution = self.imageToBuffer(substitution[placeholder.key]);
    } catch (error) {
        if (self.option && self.option.handleImageError && typeof self.option.handleImageError === "function") {
            self.option.handleImageError(substitution, error);
        } else {
            throw error;
        }
    }

    // put image to media.
    self.archive.file('xl/media/image' + maxFildId + '.jpg', toArrayBuffer(substitution), { binary: true, base64: false });
    var dimension = sizeOf(substitution);
    var imageWidth = self.pixelsToEMUs(dimension.width);
    var imageHeight = self.pixelsToEMUs(dimension.height);
    // var sheet = self.loadSheet(self.substitueSheetName);
    var imageInMergeCell = false;
    self.sheet.root.findall("mergeCells/mergeCell").forEach(function (mergeCell) {
        // If image is in merge cell, fit the image
        if (self.cellInMergeCells(cell, mergeCell)) {
            var mergeCellWidth = self.getWidthMergeCell(mergeCell, self.sheet);
            var mergeCellHeight = self.getHeightMergeCell(mergeCell, self.sheet);
            var mergeWidthEmus = self.columnWidthToEMUs(mergeCellWidth);
            var mergeHeightEmus = self.rowHeightToEMUs(mergeCellHeight);
            // Maybe we can add an option for fit image to mergecell if image is more little. Not by default
            /*if (imageWidth <= mergeWidthEmus && imageHeight <= mergeHeightEmus) {
                // Image as more little than the merge cell
                imageWidth = mergeWidthEmus;
                imageHeight = mergeHeightEmus;
            }*/
            var widthRate = imageWidth / mergeWidthEmus;
            var heightRate = imageHeight / mergeHeightEmus;
            if (widthRate > heightRate) {
                imageWidth = Math.floor(imageWidth / widthRate);
                imageHeight = Math.floor(imageHeight / widthRate);
            } else {
                imageWidth = Math.floor(imageWidth / heightRate);
                imageHeight = Math.floor(imageHeight / heightRate);
            }
            imageInMergeCell = true;
        }
    });
    if (imageInMergeCell == false) {
        var ratio = 100;
        if (self.option && self.option.imageRatio) {
            ratio = self.option.imageRatio;
        }
        if (ratio <= 0) {
            ratio = 100;
        }
        imageWidth = Math.floor(imageWidth * ratio / 100);
        imageHeight = Math.floor(imageHeight * ratio / 100);
    }
    var imagePart = etree.SubElement(drawing.root, 'xdr:oneCellAnchor');
    var fromPart = etree.SubElement(imagePart, 'xdr:from');
    var fromCol = etree.SubElement(fromPart, 'xdr:col');
    fromCol.text = (self.charToNum(self.splitRef(cell.attrib.r).col) - 1).toString();
    var fromColOff = etree.SubElement(fromPart, 'xdr:colOff');
    fromColOff.text = '0';
    var fromRow = etree.SubElement(fromPart, 'xdr:row');
    fromRow.text = (self.splitRef(cell.attrib.r).row - 1).toString();
    var fromRowOff = etree.SubElement(fromPart, 'xdr:rowOff');
    fromRowOff.text = '0';
    var extImagePart = etree.SubElement(imagePart, 'xdr:ext', { cx: imageWidth, cy: imageHeight });
    var picNode = etree.SubElement(imagePart, 'xdr:pic');
    var nvPicPr = etree.SubElement(picNode, 'xdr:nvPicPr');
    var cNvPr = etree.SubElement(nvPicPr, 'xdr:cNvPr', { id: maxId, name: 'image_' + maxId, descr: '' });
    var cNvPicPr = etree.SubElement(nvPicPr, 'xdr:cNvPicPr');
    var picLocks = etree.SubElement(cNvPicPr, 'a:picLocks', { noChangeAspect: '1' });
    var blipFill = etree.SubElement(picNode, 'xdr:blipFill');
    var blip = etree.SubElement(blipFill, 'a:blip', {
        "xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
        "r:embed": "rId" + maxId
    });
    var stretch = etree.SubElement(blipFill, 'a:stretch');
    var fillRect = etree.SubElement(stretch, 'a:fillRect');
    var spPr = etree.SubElement(picNode, 'xdr:spPr');
    var xfrm = etree.SubElement(spPr, 'a:xfrm');
    var off = etree.SubElement(xfrm, 'a:off', { x: "0", y: "0" });
    var ext = etree.SubElement(xfrm, 'a:ext', { cx: imageWidth, cy: imageHeight });
    var prstGeom = etree.SubElement(spPr, 'a:prstGeom', { 'prst': 'rect' });
    var avLst = etree.SubElement(prstGeom, 'a:avLst');
    var clientData = etree.SubElement(imagePart, 'xdr:clientData');
    return true;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants