英文:
How to export an individual slide from a presentation as a PDF using Google App Scripts?
问题
抱歉,你提供的代码中有一些HTML实体字符,我会将其删除,然后为你提供翻译:
function Email3UpPDF() {
Logger.log("Emailing!");
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var ssID = "10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y";
var shID = "g2580bcdba17_0_22";
var Addy1 = FS.getRange("N" + FS.getLastRow()).getValue();
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/presentation/d/" + ssID + "/export?format=pdf&id=" + shID; //This creates the PDF export url
var result = UrlFetchApp.fetch(url, requestData);
var contents = result.getContent();
MailApp.sendEmail(Addy1,"Local Sign Template","Here is your custom sign Template.", {attachments:[{fileName: "LST3UP.pdf", content:contents, mimeType:"application/pdf"}]});
}
请注意,你提到尝试将演示文稿ID和幻灯片ID替换到ssID
和shID
变量中,但遇到了404错误。你提到,当你将演示文稿ID同时放在ssID
和shID
变量中时,程序成功运行,但会发送包含两张幻灯片的2页PDF。你的意图是只有一页幻灯片。如果你需要帮助解决这个问题,可以提供更多关于如何选择特定幻灯片的信息。
英文:
I have a Google Spreadsheet attached to a Form. On Form Submit, a script takes information from the submission and applies it into carefully placed textboxes in a Google Slide. There are two separate forms which are used to submit information into two separate slides on the SAME presentation.
After the information is entered, the script runs a function that is supposed to export the edited slide ONLY as a PDF and email it to an address provided on the Google Form.
I had a similar setup on a different program of mine and had someone from an online forum help me write the export PDF / Email code. The code they helped me write was for exporting and emailing an individual Spreadsheet sheet.
Here is the email code that I copied from my Spreadsheet program.
function Email3UpPDF () {
Logger.log("Emailing!");
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var ssID = "10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y"
var shID = "g2580bcdba17_0_22"
var Addy1 = FS.getRange("N"+FS.getLastRow()).getValue();
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/presentation/d/"+ ssID + "/export?format=pdf&id="+shID; //This creates the PDF export url
var result = UrlFetchApp.fetch(url , requestData);
var contents = result.getContent();
MailApp.sendEmail(Addy1,"Local Sign Template" ,"Here is your custom sign Template.", {attachments:[{fileName: "LST3UP.pdf", content:contents, mimeType:"application/pdf"}]});
}
My HOPE was that I could simply substitute the Spreadsheet ID with a Presentation ID, and the Sheet ID with a Slide ID. When I tried that I was met with this error:
> Exception: Request failed for https://docs.google.com returned code 404. Truncated server response: <!DOCTYPE html><html lang="en"><head><meta name="description" content="Web word processing, presentations and spreadsheets"><meta name="viewport" c... (use muteHttpExceptions option to examine full response)
The error points to line 13: var contents = result.getContent();
I should note that when I put JUST the Presentation ID in both the ssID and the shID variables, the program runs successfully but ends up sending a 2 page PDF with both slides on it. Which makes sense to me. My intention is to only have one slide though.
答案1
得分: 2
Modified script 1:
function Email3UpPDF() {
Logger.log("Emailing!");
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var Addy1 = FS.getRange("N" + FS.getLastRow()).getValue();
var presentationId = "10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y"; // Google Slide的文件ID。
var pageObjectIds = ["g2580bcdba17_0_22"]; // Google Slide的页面对象ID。
var temp = DriveApp.getFileById(presentationId).makeCopy("temp");
var s = SlidesApp.openById(temp.getId());
s.getSlides().forEach(function (s) {
if (!pageObjectIds.includes(s.getObjectId())) {
s.remove();
}
});
s.saveAndClose();
var contents = temp.getBlob().getBytes();
temp.setTrashed(true);
MailApp.sendEmail(Addy1, "本地签名模板", "这是您的定制签名模板。", { attachments: [{ fileName: "LST3UP.pdf", content: contents, mimeType: "application/pdf" }] });
}
Modified script 2:
在此修改中,特定页面从Google幻灯片中检索并使用pdf-lib的JavaScript库转换为PDF格式。
// 参考:https://gist.github.com/tanaikech/9d77f7d634d2d31914396d7dc84b79c3
async function exportSpecificPages_(fileId, pageNumbers) {
const cdnjs = "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText()); // 加载pdf-lib
const setTimeout = function (f, t) {
Utilities.sleep(t);
return f();
}
const blob = DriveApp.getFileById(fileId).getBlob();
const pdfDoc = await PDFLib.PDFDocument.create();
const pdfData = await PDFLib.PDFDocument.load(new Uint8Array(blob.getBytes()));
const pages = await pdfDoc.copyPages(pdfData, [...Array(pdfData.getPageCount())].map((_, i) => i));
pages.forEach((page, i) => {
if (pageNumbers.includes(i + 1)) {
pdfDoc.addPage(page);
}
});
const bytes = await pdfDoc.save();
return [...new Int8Array(bytes)];
}
// 请运行此函数。
async function Email3UpPDF() {
Logger.log("Emailing!");
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var Addy1 = FS.getRange("N" + FS.getLastRow()).getValue();
var presentationId = "10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y"; // Google Slide的文件ID。
var pageObjectIds = ["g2580bcdba17_0_22"]; // Google Slide的页面对象ID。
var pages = SlidesApp.openById(presentationId).getSlides().reduce(function (ar, s, i) {
if (pageObjectIds.includes(s.getObjectId())) {
ar.push(i + 1);
}
return ar;
}, []);
var contents = await exportSpecificPages_(presentationId, pages);
MailApp.sendEmail(Addy1, "本地签名模板", "这是您的定制签名模板。", { attachments: [{ fileName: "LST3UP.pdf", content: contents, mimeType: "application/pdf" }] });
}
注意:
- 我认为上述脚本有效。但在这种情况下,当您直接复制并粘贴从https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js检索的JavaScript到您的Google Apps Script项目中时,可以减少加载的处理成本。
英文:
I'm worried that your endpoint might not be able to used for exporting the specific slide from the Google Slide as a PDF format. So, in your situation, how about the following modification?
Modified script 1:
function Email3UpPDF() {
Logger.log("Emailing!");
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var Addy1 = FS.getRange("N" + FS.getLastRow()).getValue();
var presentationId = "10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y"; // File ID of Google Slide.
var pageObjectIds = ["g2580bcdba17_0_22"]; // Page object ID of Googe Slide.
var temp = DriveApp.getFileById(presentationId).makeCopy("temp");
var s = SlidesApp.openById(temp.getId());
s.getSlides().forEach(s => {
if (!pageObjectIds.includes(s.getObjectId())) {
s.remove();
}
});
s.saveAndClose();
var contents = temp.getBlob().getBytes();
temp.setTrashed(true);
MailApp.sendEmail(Addy1, "Local Sign Template", "Here is your custom sign Template.", { attachments: [{ fileName: "LST3UP.pdf", content: contents, mimeType: "application/pdf" }] });
}
-
In this modification, the current Google Slide is copied as a temporal file. And, all slides except for the specific slide are removed. And, the temporal Google Slide is exported as a PDF format. I used this flow because I'm worried that your Google Slide might have a specific theme.
-
In this modification, when you modify
var pageObjectIds = ["g2580bcdba17_0_22"];
tovar pageObjectIds = ["g2580bcdba17_0_22", "### other page ID ###",,,];
, you can include several pages in a PDF file.
Modified script 2:
In this modification, the specific pages are retrieved from Google Slide and converted to a PDF format using a Javascript library of pdf-lib.
// Ref: https://gist.github.com/tanaikech/9d77f7d634d2d31914396d7dc84b79c3
async function exportSpecificPages_(fileId, pageNumbers) {
const cdnjs = "https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText()); // Load pdf-lib
const setTimeout = function (f, t) {
Utilities.sleep(t);
return f();
}
const blob = DriveApp.getFileById(fileId).getBlob();
const pdfDoc = await PDFLib.PDFDocument.create();
const pdfData = await PDFLib.PDFDocument.load(new Uint8Array(blob.getBytes()));
const pages = await pdfDoc.copyPages(pdfData, [...Array(pdfData.getPageCount())].map((_, i) => i));
pages.forEach((page, i) => {
if (pageNumbers.includes(i + 1)) {
pdfDoc.addPage(page);
}
});
const bytes = await pdfDoc.save();
return [...new Int8Array(bytes)];
}
// Please run this function.
async function Email3UpPDF() {
Logger.log("Emailing!");
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var Addy1 = FS.getRange("N" + FS.getLastRow()).getValue();
var presentationId = "10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y"; // File ID of Google Slide.
var pageObjectIds = ["g2580bcdba17_0_22"]; // Page object ID of Googe Slide.
var pages = SlidesApp.openById(presentationId).getSlides().reduce((ar, s, i) => {
if (pageObjectIds.includes(s.getObjectId())) {
ar.push(i + 1);
}
return ar;
}, []);
var contents = await exportSpecificPages_(presentationId, pages);
MailApp.sendEmail(Addy1, "Local Sign Template", "Here is your custom sign Template.", { attachments: [{ fileName: "LST3UP.pdf", content: contents, mimeType: "application/pdf" }] });
}
Note:
- I think that the above script works. But, in this case, when you directly copy and paste the Javascript retrieved from https://cdn.jsdelivr.net/npm/pdf-lib/dist/pdf-lib.min.js to your Google Apps Script project, the process cost for loading it can be reduced.
答案2
得分: 1
替代方法
我找到了这篇相关的帖子,你可以利用其中提到的特定方法来解决这个问题。我已经对你的脚本进行了微调,并在我的端口进行了快速测试。
示例微调脚本
function extractPdfData() {
Logger.log("Emailing!");
//Replace this with your API key, this is my temporary limited 'api key' for testing purposes.
const apiSecret = 'ZQ2A9pbkh6w3xuBY';
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var ssID = '10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y';
//define the number of slide page(s) that you want. E.g. slide number '2'
var pages = [2].join('%2C');
var Addy1 = FS.getRange("N"+FS.getLastRow()).getValue();
var requestData = { "method": "GET", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() } };
var pdfUrl = "https://docs.google.com/presentation/d/" + ssID + "/export?format=pdf";
var slidePDF = UrlFetchApp.fetch(pdfUrl, requestData).getBlob();
//Retrieve the number of PDF page(s) you only want to attach on your email.
var pdfPages = processPDF(apiSecret, pages, slidePDF);
//Send the page(s) in your email
pdfPages.forEach(page => MailApp.sendEmail(Addy1,"Local Sign Template","Here is your custom sign Template.", {attachments:[{fileName: "LST3UP.pdf", content:UrlFetchApp.fetch(page.Url).getContent(), mimeType:"application/pdf"}]}));
}
//Utilizing the 'convertapi' method
processPDF(apiSecret, pages, slidePDF) {
var url = `https://v2.convertapi.com/convert/pdf/to/split?Secret=${apiSecret}&ExtractPages=${pages}&StoreFile=true`;
var options = {
method: "post",
payload: { File: slidePDF },
}
var res = UrlFetchApp.fetch(url, options);
var rawData = JSON.parse(res.getContentText());
return rawData.Files;
}
演示
虚拟幻灯片。
例如:您只希望将幻灯片编号2作为唯一的PDF文件发送给您的收件人。
运行脚本后。
我的虚拟电子邮件账户收到了这封电子邮件:
整个PDF附件只包含幻灯片编号2:
英文:
Alternative Method
I have found this related post that you could utilise to work around this matter using a specific method mentioned in the post. I have tweaked your script below & performed a quick test run on my end.
Sample Tweaked Script
function extractPdfData() {
Logger.log("Emailing!");
//Replace this with your API key, this is my temporary limited 'api key' for testing purposes.
const apiSecret = 'ZQ2A9pbkh6w3xuBY';
var Sapp = SpreadsheetApp;
var FS = Sapp.getActiveSpreadsheet().getSheetByName("3UP Submissions");
var ssID = '10Up_PcLxVopXont9Qcu-yk-PrFGWfWPQ3ETsgys4v0Y';
//define the number of slide page(s) that you want. E.g. slide number '2'
var pages = [2].join('%2C');
var Addy1 = FS.getRange("N"+FS.getLastRow()).getValue();
var requestData = { "method": "GET", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() } };
var pdfUrl = "https://docs.google.com/presentation/d/" + ssID + "/export?format=pdf";
var slidePDF = UrlFetchApp.fetch(pdfUrl, requestData).getBlob();
//Retrieve the number of PDF page(s) you only want to attach on your email.
var pdfPages = processPDF(apiSecret, pages, slidePDF);
//Send the page(s) in your email
pdfPages.forEach(page => MailApp.sendEmail(Addy1,"Local Sign Template" ,"Here is your custom sign Template.", {attachments:[{fileName: "LST3UP.pdf", content:UrlFetchApp.fetch(page.Url).getContent(), mimeType:"application/pdf"}]}));
}
//Utilizing the 'convertapi' method
processPDF(apiSecret, pages, slidePDF) {
var url = `https://v2.convertapi.com/convert/pdf/to/split?Secret=${apiSecret}&ExtractPages=${pages}&StoreFile=true`;
var options = {
method: "post",
payload: { File: slidePDF },
}
var res = UrlFetchApp.fetch(url, options);
var rawData = JSON.parse(res.getContentText());
return rawData.Files;
}
Demo
> Dummy Slide. <br> E.g. you want the slide number 2 to be the only PDF file sent to your recipient.
> After running the script. <br> My dummy email account received this email:
> The whole PDF attachment is only the slide number 2:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论