Search code examples
google-apps-scriptgoogle-drive-apibase64blobgoogle-docs

getBlob() causing "Invalid image data." Error. Google Apps Script


My objective is to.

  1. fetch a base64 image string from a google doc
  2. save it to the drive as an image
  3. getblob from image and insert the new image into the same doc as a real image.
function getImage(doc) {
    var tempBase64 = doc.getBody().getParagraphs()[doc.getBody().getParagraphs().length - 1].getText();
    var base64 = tempBase64.replace("data:image/svg+xml;base64,", "");
    var decoded = Utilities.base64Decode(base64);
    return decoded;
}

function run() {
    var doc = DocumentApp.getActiveDocument();
    var img = getImage(doc); //returns decoded blob
    var body = DocumentApp.getActiveDocument().getBody();
    //gets the name of the current doc
    var filename = DriveApp.getFileById(DocumentApp.getActiveDocument().getId());
    var blobImg = Utilities.newBlob(img, MimeType.SVG, filename);
    var currentFolder = DriveApp.getFolderById("1UuP2vZNXLVtgrZxAHLSNZUqVnx0xeSgW");
    //saves image as same name
    var newimg = currentFolder.createFile(blobImg).getId();
    //wait for image to save
    Utilities.sleep(5 * 1000);
    // get blob 
    var blob = DriveApp.getFileById(newimg).getBlob();
    var cursor = doc.getCursor();
    if (cursor) {
    //insert in to doc
        cursor.insertInlineImage(blob);
    }

}

function onOpen() {
    run();
}

Currently it's reading the doc and fetching the base64 string ✓ eg:

image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iMTIiIGhlaWdodD0iMTUiPjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9InJnYigwLCAwLCAxMzkpIiBmaWxsPSJub25lIiBkPSJNIDEgMyBsIDEgNCIvPjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9InJnYigwLCAwLCAxMzkpIiBmaWxsPSJub25lIiBkPSJNIDggMSBsIDEgMSIvPjxwYXRoIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9InJnYigwLCAwLCAxMzkpIiBmaWxsPSJub25lIiBkPSJNIDMgMTAgYyAwLjAyIDAuMDcgMC4zMSAzLjU0IDEgNCBjIDAuODQgMC41NiAzLjg5IDAuNDcgNSAwIGMgMC44IC0wLjM0IDIgLTMgMiAtMyIvPjwvc3ZnPg==

It's saving as an image in a particular folder ✓

It's returning the id of the new image.✓

It's getting the image as a blob ✓

When it comes to inserting the image, i'm getting Invalid image data. (line 20, file "Code"). Literally no idea how to resolve. Anyone help?


Solution

  • I think that your script is correct. There is only one issue. In the current stage, the images with the mimeType of image/svg+xml cannot be directly inserted to Google Document yet. So it is required to convert from svg image to other mimeType. In this modification, I convert to image/png using Drive API. Also there are several APIs, which is not Google APIs, for converting svg to others. I think that there are several workarounds in your situation. So please think of this as just one of them.

    Modification points:

    • Retrieve file ID from the created file and retrieve the thumbnailLink using Drive API.
    • After the image size of the link is adjusted, retrieve the image blob of PNG.
      • It has already been found that by modifying the query parameter of =s###, the image size can be modified. I used this. Ref
    • Put the PNG blob to Document.

    Modified script:

    In this modified script, run() was modified. Please confirm the following modified script.

    function run() {
      var doc = DocumentApp.getActiveDocument();
      var img = getImage(doc); //returns decoded blob
      var body = DocumentApp.getActiveDocument().getBody();
      //gets the name of the current doc
      var filename = DriveApp.getFileById(DocumentApp.getActiveDocument().getId());
      var blobImg = Utilities.newBlob(img, MimeType.SVG, filename);
      var currentFolder = DriveApp.getFolderById("1UuP2vZNXLVtgrZxAHLSNZUqVnx0xeSgW");
      //saves image as same name
      var newimg = currentFolder.createFile(blobImg).getId();
      //wait for image to save
      Utilities.sleep(5 * 1000);
      // get blob
    
      // --- Added --- Begin
      var width = 300; // width of the image. A value of 300 pixels was used as a sample.
      var url = "https://www.googleapis.com/drive/v3/files/" + newimg + "?fields=thumbnailLink&access_token=" + ScriptApp.getOAuthToken();
      var link = JSON.parse(UrlFetchApp.fetch(url).getContentText()).thumbnailLink.replace(/=s\d+/, "=s" + width);
      var blob = UrlFetchApp.fetch(link).getBlob();
      // --- Added --- End
    
      var cursor = doc.getCursor();
      if (cursor) {
      //insert in to doc
          cursor.insertInlineImage(blob);
      }
    }
    

    Note:

    • The width and height of the svg image cannot be retrieved by Drive API. So in this modification, I used the constant width.
    • I think that in your script, Drive API can be used. But if an error related to API occurs, please enable Drive API at API console.

    Reference:

    If this was not the result you want, I apologize.