如何在谷歌文档/谷歌应用程序脚本中删除pdf导出的白色背景层



我遇到了谷歌应用程序脚本/谷歌文档的问题。我想做一个插件,用API为谷歌文档添加水印。这很好,但前提是我把水印放在文档前面。如果我把它放在文档后面,水印就看不见了。然后我试着在LibreOffice Draw中查看不同的图层,在那里我看到谷歌文档在文本后面放了一些白色图层,这些图层位于水印之上。

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

我还试图通过谷歌应用程序脚本将页面的背景设置为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);

但这并没有奏效。

这是一个测试文档,你可以看到背景中的白色层,就像在libre办公室的抽屉里一样。

提前感谢。

以下是谷歌应用程序脚本插件的代码:

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 + "rn";
data += "Content-Disposition: form-data; name="" + i + ""; rnrn" + metadata[i] + "rn";
}
data += "--" + boundary + "rn";
data += "Content-Disposition: form-data; name="file"; filename="" + file.getName() + ""rn";
data += "Content-Type:" + file.getMimeType() + "rnrn";
var payload = Utilities.newBlob(data).getBytes()
.concat(file.getBlob().getBytes())
.concat(Utilities.newBlob("rn--" + 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 file.pdf output output.pdf uncompress
    
  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,然后绘制一个或多个带有填充背景f的大矩形re

    您想删除或注释(%(的所有这些行

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

    pdftk edited.pdf output final.pdf compress
    

这是PDF语言参考的链接。只需使用字母索引查找运算符,如ref,就可以了解它们的作用

最新更新