【问题标题】:Copied Image from Google Document Paragraph inserted twice从 Google 文档段落复制的图像插入两次
【发布时间】:2019-08-22 10:08:12
【问题描述】:

我正在尝试将多个 Google 文档合并到一个文档中,但原始文档中的图像被插入了两次。一个在正确的位置,另一个在新创建的文档的末尾。

据我所见,这些图片被脚本检测为Paragraph

正如您在下面的代码中看到的那样,我受到了此处发现的类似主题的启发。 其中一位建议在Paragraph Element 中搜索child Element,但调试显示没有。文档的相关部分将始终使用 appendParagraph 方法插入,因为脚本无法正确检测图像。

这就是为什么我发现的其他相关主题在这里不起作用:它建议在段落本身之前插入图像但它无法检测到它。

使用来自 Stackdriver 的默认 Loggerconsole.log 进行日志记录将显示类型为段落的对象。 一步一步的执行没有显示任何循环调用appendParagraph方法两次。

/* chosenParts contains list of Google Documents name */
function concatChosenFiles(chosenParts) {
  var folders = DriveApp.getFoldersByName(folderName);
  var folder = folders.hasNext() ? folders.next() : false;
  var parentFolders = folder.getParents();
  var parentFolder = parentFolders.next();
  var file = null;
  var gdocFile = null;
  var fileContent = null;
  var offerTitle = "New offer";
  var gdocOffer = DocumentApp.create(offerTitle); 
  var gfileOffer = DriveApp.getFileById(gdocOffer.getId()); // transform Doc into File in order to choose its path with DriveApp
  var offerHeader = gdocOffer.addHeader();
  var offerContent = gdocOffer.getBody();
  var header = null;
  var headerSubPart = null;
  var partBody= null;
  var style = {};

  parentFolder.addFile(gfileOffer); // place current offer inside generator folder
  DriveApp.getRootFolder().removeFile(gfileOffer); // remove from home folder to avoid copy

  for (var i = 0; i < chosenParts.length; i++) {
    // First retrieve Document to combine
    file = folder.getFilesByName(chosenParts[i]);
    file = file.hasNext() ? file.next() : null;
    gdocFile = DocumentApp.openById(file.getId());

    header = gdocFile.getHeader();
    // set Header from first doc
    if ((0 === i) && (null !== header)) {
      for (var j = 0; j < header.getNumChildren(); j++) {
        headerSubPart = header.getChild(j).copy();
        offerHeader.appendParagraph(headerSubPart); // Assume header content is always a paragraph
      }
    }

    fileContent = gdocFile.getBody();

    // Analyse file content and insert each part inside the offer with the right method
    for (var j = 0; j < fileContent.getNumChildren(); j++) {

      // There is a limit somewhere between 50-100 unsaved changed where the script
      // wont continue until a batch is commited.
      if (j % 50 == 0) {
        gdocOffer.saveAndClose();
        gdocOffer = DocumentApp.openById(gdocOffer.getId());
        offerContent = gdocOffer.getBody();
      }

      partBody = fileContent.getChild(j).copy();     
      switch (partBody.getType()) {
        case DocumentApp.ElementType.HORIZONTAL_RULE:
          offerContent.appendHorizontalRule();
          break;
        case DocumentApp.ElementType.INLINE_IMAGE:
          offerContent.appendImage(partBody);
          break;
        case DocumentApp.ElementType.LIST_ITEM:
          offerContent.appendListItem(partBody);
          break;
        case DocumentApp.ElementType.PAGE_BREAK:
          offerContent.appendPageBreak(partBody);
          break;
        case DocumentApp.ElementType.PARAGRAPH:
          // Search for image inside parapraph type
          if (partBody.asParagraph().getNumChildren() != 0 && partBody.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) 
          {
            offerContent.appendImage(partBody.asParagraph().getChild(0).asInlineImage().getBlob());
          } else {
            offerContent.appendParagraph(partBody.asParagraph());
          }
          break;
        case DocumentApp.ElementType.TABLE:
          offerContent.appendTable(partBody);
          break;
        default:
          style[DocumentApp.Attribute.BOLD] = true;
          offerContent.appendParagraph("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.").setAttributes(style);
          console.log("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.");
          Logger.log("Element type '" + partBody.getType() + "' from '" + file.getName() + "' could not be merged.");
      }
    }
    // page break at the end of each part.
    offerContent.appendPageBreak();
  }
}

无论组合多少文件都会出现问题,使用一个就足以重现。

如果文件中只有一个图像(没有空格或换行),并且之后没有使用“appendPageBreak”,则不会发生。当某些文本位于图像旁边时,图像就会被复制。

最后一件事:有人建议这是“由于格式的自然继承”,但我没有找到如何防止这种情况。

非常感谢所有能够查看此内容的人 :)

编辑:我在@ziganotschka 建议之后修改了段落部分

它与this subject 非常相似,只是它的解决方案在这里不起作用。

这是新的代码:


        case DocumentApp.ElementType.PARAGRAPH:
          // Search for image inside parapraph type
          if(partBody.asParagraph().getPositionedImages().length) {
            // Assume only one image per paragraph (@TODO : to improve)
            tmpImage = partBody.asParagraph().getPositionedImages()[0].getBlob().copyBlob();
            // remove image from paragraph in order to add only the paragraph
            partBody.asParagraph().removePositionedImage(partBody.asParagraph().getPositionedImages()[0].getId());
            tmpParagraph = offerContent.appendParagraph(partBody.asParagraph());
            // Then add the image afterward, without text
            tmpParagraph.addPositionedImage(tmpImage);

          } else if (partBody.asParagraph().getNumChildren() != 0 && partBody.asParagraph().getChild(0).getType() == DocumentApp.ElementType.INLINE_IMAGE) {
            offerContent.appendImage(partBody.asParagraph().getChild(0).asInlineImage().getBlob());
          } else {
            offerContent.appendParagraph(partBody.asParagraph());
          }
          break;

不幸的是,它仍然复制图像。如果我注释插入图像的行 (tmpParagraph.addPositionedImage(tmpImage);),则根本不会插入任何图像。

编辑 2:这是 Google App Script 中的一个已知错误

https://issuetracker.google.com/issues/36763970

请参阅 cmets 了解一些解决方法。

【问题讨论】:

  • 我复制了你的代码,没有遇到你描述的行为。您能否提供一个样本文档以允许重现该问题?
  • 感谢您的宝贵时间;我很惊讶您无法重现:-/ 这是触发错误行为的文件的链接:docs.google.com/document/d/…

标签: google-apps-script google-docs


【解决方案1】:

您的图片嵌入为“换行文字”,而不是 Inline image

这就是您无法使用getBody().getImages(); 检索它的原因

相反,您可以使用getBody().getParagraphs();[index].getPositionedImages() 检索它

我不确定为什么您的图像被复制了两次,但作为一种解决方法,您可以复制图像并将其作为内联图像插入

getBody().insertImage(childIndex, getBody().getParagraphs()[index].getPositionedImages()[index].copy());

然后

getBody().getParagraphs()[index].getPositionedImages()[index].removeFromParent();

显然,您需要遍历所有段落并检查每个段落是否嵌入了positioned images,以便使用正确的索引检索它们并继续。

【讨论】:

  • 再次感谢您的宝贵时间 :) 通过您建议的调整,图像不会被复制,而是添加为InlineImage(这是insertImage 的正确行为)。但是InlineImage 改变了我在原始文档中的格式,我希望保留它。不过,您对图像是“定位图像”是正确的,所以我尝试使用它。不幸的是,问题仍然存在。我将调整我的原始帖子以考虑到这一点。
  • 不幸的是,我不知道定位图像有什么问题。这可能是一个错误,因此我建议您将其提交到公共问题跟踪器issuetracker.google.com。同时,您需要使用解决方法。如果将定位图像转换为内联图像不适合您,您可能会考虑在合并之前将您的文档转换为 pdf(一旦合并,您可以使用 OCR 将它们转换回文档文件)。
  • 感谢分享问题跟踪器,我不知道它的存在。我发现了其中提到的错误,不确定他们会对此做些什么:issuetracker.google.com/issues/36763970 无论如何,感谢您的时间和建议!
【解决方案2】:

在添加所有其他元素后,在脚本末尾添加 PositionedImages。根据我的经验,如果在图像定位段落之后将其他元素添加到文档中,则会添加额外的图像。

您可以通过存储对将用作图像持有者的段落元素的引用以及图像中的 blob 以及任何信息(高度、宽度等)来完成此操作。然后在您的脚本结束时,只需遍历存储的引用并添加图像。

var imageParagraphs = [];    

...

case DocumentApp.ElementType.PARAGRAPH:
    var positionedImages = element.getPositionedImages();  
    if (positionedImages.length > 0){
      var imageData = [];
      for each(var image in positionedImages){
        imageData.push({
          height: image.getHeight(),
          width: image.getWidth(),
          leftOffset: image.getLeftOffset(),
          topOffset: image.getTopOffset(),
          layout: image.getLayout(),
          blob: image.getBlob()
        });
        element.removePositionedImage(image.getId());
      }  
      var p = merged_doc_body.appendParagraph(element.asParagraph());
      imageParagraphs.push({element: p, imageData: imageData});
    }
    else
      merged_doc_body.appendParagraph(element);
  break; 

...

for each(var p in imageParagraphs){
  var imageData = p.imageData
  var imageParagraph = p.element      
  for each(var image in imageData){
    imageParagraph.addPositionedImage(image.blob)
      .setHeight(image.height)
      .setWidth(image.width)
      .setLeftOffset(image.leftOffset)
      .setTopOffset(image.topOffset)
      .setLayout(image.layout);                
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 2012-05-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多