如何在 google docs / google apps 脚本中删除 pdf 导出的白色背景层?

How can I remove the white background layers of a pdf export in google docs / google apps script?

我遇到了 google 应用程序脚本/google 文档的问题。我想制作一个插件,用 API 向 google docs 文档添加水印。效果很好,但前提是我将水印放在文档前面。如果我把它放在文件后面,水印是不可见的。然后我试着查看 LibreOffice Draw 中的不同图层,我看到 google 文档在文本后面放置了一些白色图层,这些图层在水印上方。

那么有人知道吗,我如何在没有白色图层的情况下从 google 文档中导出 pdf 文件?

我还尝试通过 google apps 脚本将页面背景设置为 null 或 rgba(0,0,0,0.0),如下所示:

var highlightStyle = {};
highlightStyle[DocumentApp.Attribute.BACKGROUND_COLOR] = "rgba(0,0,0,0.0)";
let editedText = DocumentApp.getActiveDocument().getBody().editAsText().setAttributes(highlightStyle);

但是没有用。

Here is a test document,您可以在其中看到背景中的白色图层,就像在自由办公抽屉中一样。

在此先致谢。

这里是 google 应用程序脚本插件的代码:

    function base64Encode(str) {
    var encoded = Utilities.base64EncodeWebSafe(Utilities.newBlob(str).getBytes());
    return encoded.replace(/=+$/, '');
};

function encodeJWT(public, secret) {
    var header = JSON.stringify({
        typ: 'JWT',
        alg: 'HS256',
      jti: public
    });
    var encodedHeader = base64Encode(header);
    var iat = new Date().getTime() / 1000 - 60;
    var payload = JSON.stringify({
        iat: iat,
      iss: 'name',
      jti: public,
      public_key: public
    });
    var encodedPayload = base64Encode(payload);
    var toSign = [encodedHeader, encodedPayload].join('.');
    var signature = Utilities.computeHmacSha256Signature(toSign, secret);
    var encodedSignature = base64Encode(signature);
    return [toSign, encodedSignature].join('.');
};


function onInstall(){
  onOpen();
}

function onOpen(){
  let menu = DocumentApp.getUi().createAddonMenu().addItem("Merge PDFs", "showSidebar").addToUi();
}

let folderName = "watermark data";
let fileName = "watermark template";

function showSidebar(){
  var html = HtmlService.createTemplateFromFile("index").evaluate().setTitle("PDF Creator");
  
  DocumentApp.getUi().showSidebar(html);
}

function mergePdf(transparency){
  var highlightStyle = {};
  highlightStyle[DocumentApp.Attribute.BACKGROUND_COLOR] = "#ffffff";
  let editedText = DocumentApp.getActiveDocument().getBody().editAsText().setAttributes(highlightStyle);
  
  
  let folders = DriveApp.getFoldersByName(folderName);
  if(!folders.hasNext()){
    DriveApp.getRootFolder().createFolder(folderName) 
  }
  
  let files = DriveApp.getFilesByName(fileName);
  if(files.hasNext()){
    let header;
    if(DocumentApp.getActiveDocument().getHeader()){
      header = DocumentApp.getActiveDocument().getHeader();
    }else{
      header = DocumentApp.getActiveDocument().addHeader();
    }
    
  }
  fetchAPIData("https://api.ilovepdf.com/v1/auth", "post", {
    "public_key": "api_key"
  });
  

  let startData = JSON.parse(fetchAPIData("https://api.ilovepdf.com/v1/start/watermark", "get"));
  let uploadData1 = JSON.parse(requestAPI(convertPDF(), "https://" + startData.server + "/v1/upload", {
                                         "task": startData.task
                                         }));
    let file = DriveApp.getFilesByName(fileName + ".png");
  let file2 = DriveApp.getFilesByName(fileName + ".jpg");
  let file3 = DriveApp.getFilesByName(fileName + ".jpeg");
  if(file.hasNext()){
     file = file.next().getId();
  }else if(file2.hasNext()){
     file = file2.next().getId();
  }else if(file3.hasNext()){
     file = file3.next().getId();
  }else{
    DocumentApp.getUi().alert("Error, watermark not found!\n Please upload a watermark!");
  }
  let uploadData2 = JSON.parse(requestAPI(file, "https://" + startData.server + "/v1/upload", {
                                         "task": startData.task
                                         }));
//  DocumentApp.getUi().alert(typeof transparency);
  let processResponse = JSON.parse(fetchAPIData("https://" + startData.server + "/v1/process", "post",{
                                         "task": startData.task,
                                         "tool": "watermark",
                                         "files": [
                                         {
                                         "server_filename": uploadData1.server_filename,
                                         "filename": "Test"
                                         }                                       
                                         ],
                                         "mode": "image",
                                         "layer": "below",
                                         "image": uploadData2.server_filename,
                                                "transparency": transparency
                                         }));
  if(processResponse.status == "TaskSuccess"){
    let responseData = fetchAPIData("https://" + startData.server + "/v1/download/" + startData.task, "get");
    if(responseData){
      file = DriveApp.getRootFolder().createFile(responseData.getAs('application/pdf'));
      file.setName(DocumentApp.getActiveDocument().getName());
      DocumentApp.getUi().alert('You can download your pdf file here: ' + file.getDownloadUrl());
      var actionResponse = CardService.newActionResponseBuilder()
      .setOpenLink(CardService.newOpenLink()
                   .setUrl(file.getDownloadUrl())
                   .setOpenAs(CardService.OpenAs.FULL_SIZE)
                   .setOnClose(CardService.OnClose.NOTHING))
      .build();
    }else{
      DocumentApp.getUi().alert("Error, the API Request wasn't successful!");
    }
  }
}



function fetchAPIData(route, method, data){

  var options = {method: method};
  if(data){
    options = {
      'method' : method,
      'headers': {
        'Authorization': 'Bearer ' +  encodeJWT("api_key", "api_key")
      },
      'contentType': 'application/json',
      // Convert the JavaScript object to a JSON string.
      'payload' : JSON.stringify(data)
    };
  }else{
    options = {
      'method' : method,
      'headers': {
        'Authorization': 'Bearer ' +  encodeJWT("api_key", "api_key")
      }
    };
  }

  var response = UrlFetchApp.fetch(route, options); 
  return response;
}


function requestAPI(fileId, url, metadata) {
  var file = DriveApp.getFileById(fileId);
  var boundary = "name";
  var data = "";
  for (var i in metadata) {
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"" + i + "\"; \r\n\r\n" + metadata[i] + "\r\n";
  }
  data += "--" + boundary + "\r\n";
  data += "Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n";
  data += "Content-Type:" + file.getMimeType() + "\r\n\r\n";
  var payload = Utilities.newBlob(data).getBytes()
    .concat(file.getBlob().getBytes())
    .concat(Utilities.newBlob("\r\n--" + boundary + "--").getBytes());
   var options = {
    method : "post",
    contentType : "multipart/form-data; boundary=" + boundary,
    payload : payload,
    muteHttpExceptions: true,
      'headers': {
        'Authorization': 'Bearer ' +  encodeJWT("api_key", "api_key")
      }
  };
  var res = UrlFetchApp.fetch(url, options).getContentText();

  Logger.log(res);
  return res;
}

function convertPDF() {
  doc = DocumentApp.getActiveDocument();
  var ui = DocumentApp.getUi();
    docblob = DocumentApp.getActiveDocument().getAs('application/pdf');
    /* Add the PDF extension */
    docblob.setName(doc.getName() + ".pdf");
    let file = DriveApp.getFoldersByName(folderName);
    if(!file.hasNext()){
      DriveApp.getRootFolder().createFolder(folderName) 
    }
    var files = DriveApp.getFilesByName(doc.getName() + ".pdf");
    while (files.hasNext()) {
      files.next().setTrashed(true);
    }
    file = DriveApp.getFoldersByName(folderName).next().createFile(docblob);
  return file.getId();
}

function saveFile(obj) {
    var files = DriveApp.getFilesByName(fileName + ".jpg");
    while (files.hasNext()) {
      files.next().setTrashed(true);
    }
    files = DriveApp.getFilesByName(fileName + ".png");
    while (files.hasNext()) {
      files.next().setTrashed(true);
    }
  var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, fileName + "." + obj.mimeType.split("/")[1]);
  DocumentApp.getUi().alert("Watermark is uploaded successfully!");
  return DriveApp.getFoldersByName(folderName).next().createFile(blob).getId();
}

我用的水印api是ilovepdfapi

我最终手动删除了背景:

  1. 使用任何合适的工具解压缩 PDF(我使用 pdftk

    pdftk source.pdf output decompressed.pdf decompress
    
  2. 使用任何手动或自动文本编辑器编辑解压缩的 PDF(我使用 Vim)

    您正在查找如下所示的代码块:

    1 1 1 RG 1 1 1 rg
    /G3 gs
    0 1123 794 1123 re
    f
    0 1123 794 1123 re
    f
    0 0 794 6738 re
    f
    

    即设置背景色为白色1 1 1 rg然后绘制一个或多个大矩形re填充背景f

    您想删除或评论 (%) 所有这些行

  3. 使用 PDF 查看器检查文件并可选择重新压缩它:

    pdftk edited.pdf output final.pdf compress
    

这里是 link 到 PDF language reference。只需使用字母索引查找运算符,例如 ref,了解它们的作用。