Update/Replace inline image on Google Document

☆樱花仙子☆ 提交于 2020-07-05 03:45:12

问题


I'm trying to set a feature to update images on a Google Document, the same way Lucidchart Add-on does on its "Updated inserted diagram" feature. For this, I'm current doing the following:

  • Creating a Named Range and storing its id on document properties, together with the data to generate the image, for later retrieve.
  • On update, call body.getNamedRangeById() and replace the element with the new generated image.

This works, but I have the following problems that does not happen with Lucidchart:

  • Every update, a blank line is added after the image.
  • If the user drag and drop the image inside document for reposition it, the Named Range disappears and I'm not able to retrieve it later.
  • If the user centralize the image, after update the image comes back to left position, even copying its attributes

Does anybody knows a good strategy to replace/update a referenced image on Google Docs, the same way Lucidchart add-on update feature works?

Thanks


回答1:


NamedRanges indeed get lost when the range is moved, so they're not very good for your scenario. But there's no other way of identifying elements (which is a great misfeature of Google Docs).

In the case of an image you could use its LINK_URL to identify it, which seems to be what Lucidchart uses. It does not get in the way of the user, so it may be a good solution.

About getting a blank line and losing attributes when inserting an image, I imagine (since you haven't shared any code) you're inserting the image directly in the document body instead of a paragraph. Then a paragraph gets created automatically to wrap your image resulting in the blank line and lost of attributes.

Here's some code example:

function initialInsert() {
  var data = Charts.newDataTable().addColumn(
    Charts.ColumnType.STRING, 'Fruits').addColumn(
    Charts.ColumnType.NUMBER, 'Amount').addRow(
    ['Apple',15]).addRow(
    ['Orange',6]).addRow(
    ['Banana',14]).build();
  var chart = Charts.newPieChart().setDataTable(data).build();

  var body = DocumentApp.getActiveDocument().getBody()
  body.appendImage(chart).setLinkUrl('http://mychart');
  //here we're inserting directly in the body, a wrapping paragraph element will be created for us
}

function updateImage() {
  var data = Charts.newDataTable().addColumn(
    Charts.ColumnType.STRING, 'Fruits').addColumn(
    Charts.ColumnType.NUMBER, 'Amount').addRow(
    ['Apple',Math.floor(Math.random()*31)]).addRow( //random int between 0 and 30
    ['Orange',Math.floor(Math.random()*31)]).addRow(
    ['Banana',Math.floor(Math.random()*31)]).build();
  var chart = Charts.newPieChart().setDataTable(data).build();

  var img = getMyImg(DocumentApp.getActiveDocument().getBody(), 'http://mychart');
  //let's insert on the current parent instead of the body 
  var parent = img.getParent(); //probably a paragraph, but does not really matter
  parent.insertInlineImage(parent.getChildIndex(img)+1, chart).setLinkUrl('http://mychart');
  img.removeFromParent();
}

function getMyImg(docBody, linkUrl) {
  var imgs = docBody.getImages();
  for( var i = 0; i < imgs.length; ++i )
    if( imgs[i].getLinkUrl() === linkUrl )
      return imgs[i];
  return null;
}

About the link_url, you could of course do like Lucidchart does and link back to your site. So it's not just broken for the user.




回答2:


Take a look at my add-on called PlantUML Gizmo.

Here's the code to the insert image function, which deals with replacing images if there's already one selected:

function insertImage(imageDataUrl, imageUrl) {
  /*
   * For debugging cursor info
   */
//  var cursor = DocumentApp.getActiveDocument().getCursor();
//  Logger.log(cursor.getElement().getParent().getType());
//  throw "cursor info: " + cursor.getElement().getType() + " offset = " + cursor.getOffset() + " surrounding text = '" + cursor.getSurroundingText().getText() + "'  parent's type = " + 
//    cursor.getElement().getParent().getType();
  /*
   * end debug
   */
  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var replaced = false;
  if (selection) {
    var elements = selection.getSelectedElements();
    // delete the selected image (to be replaced)
    if (elements.length == 1 &&
        elements[0].getElement().getType() ==
        DocumentApp.ElementType.INLINE_IMAGE) {
          var parentElement = elements[0].getElement().getParent();  // so we can re-insert cursor
          elements[0].getElement().removeFromParent();
          replaced = true;
          // move cursor to just before deleted image
          doc.setCursor(DocumentApp.getActiveDocument().newPosition(parentElement, 0));
     } else {
          throw "Please select only one image (image replacement) or nothing (image insertion)"
     }
  }
  var cursor = doc.getCursor();
  var blob;

  if (imageDataUrl != "") {
    blob = getBlobFromBase64(imageDataUrl);
  } else {
    blob = getBlobViaFetch(imageUrl);
  }

  var image = cursor.insertInlineImage(blob);  

  image.setLinkUrl(imageUrl);

  // move the cursor to after the image
  var position = doc.newPosition(cursor.getElement(), cursor.getOffset()+1);
  doc.setCursor(position);

  if (cursor.getElement().getType() == DocumentApp.ElementType.PARAGRAPH) {
    Logger.log("Resizing");
    // resize if wider than current page
    var currentParagraph = DocumentApp.getActiveDocument().getCursor().getElement().asParagraph();
    var originalImageWidth = image.getWidth();  // pixels
    var documentWidthPoints = DocumentApp.getActiveDocument().getBody().getPageWidth() - DocumentApp.getActiveDocument().getBody().getMarginLeft() - DocumentApp.getActiveDocument().getBody().getMarginRight();
    var documentWidth = documentWidthPoints * 96 / 72;  // convert to pixels (a guess)
    var paragraphWidthPoints = documentWidthPoints - currentParagraph.getIndentStart() - currentParagraph.getIndentEnd();
    var paragraphWidth = paragraphWidthPoints * 96 / 72;  // convert to pixels (a guess)

    if (originalImageWidth > paragraphWidth) {
      image.setWidth(paragraphWidth);
      // scale proportionally
      image.setHeight(image.getHeight() * image.getWidth() / originalImageWidth);  
    }

  }

}


来源:https://stackoverflow.com/questions/26597379/update-replace-inline-image-on-google-document

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!