This question already has answers here:
Export a range as a PDF in Google Apps Script
(3 answers)
Closed 6 months ago.
I'm trying to take a screenshot of a range of cells in Google spreadsheet every time a value changes in that range and save the screenshot in a URL or in my drive as .jpg, .png or pdf
I was able to find something similar for taking screenshots of charts but wasn't able to modify the script successfully for this case, has anyone done something similar
Take this as a reference, modify if needed:
Code:
function exportPdf(e) {
var spreadsheet = e.source;
var sheet = spreadsheet.getActiveSheet();
var range = e.range;
// sample dimension to be checked is B2:E5
var checkDimension = {
startingRow: 2,
startingColumn: 2,
endingRow: 5,
endingColumn: 5
};
// range should be within checkDimension and Sheet1
if(sheet.getSheetName() == 'Sheet1' &&
range.getRow() >= checkDimension.startingRow &&
range.getLastRow() <= checkDimension.endingRow &&
range.getColumn() >= checkDimension.startingColumn &&
range.getLastColumn() <= checkDimension.endingColumn) {
var spreadsheetId = spreadsheet.getId();
var sheetId = sheet.getSheetId();
var exportRange = "B2:E5";
var urlString = 'export?exportFormat=pdf&format=pdf' +
'&gid=' + sheetId + '&id=' + spreadsheetId +
'&range=' + exportRange +
'&size=A4' + // paper size
'&portrait=true'; // orientation, false for landscape
// See https://webapps.stackexchange.com/questions/130654/all-google-docs-url-parameters-functions-commands for more url parameters
var exportUrl = spreadsheet.getUrl().replace(/edit.*$/, urlString);
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
},
muteHttpExceptions: true
}
var response = UrlFetchApp.fetch(exportUrl, options);
if (response.getResponseCode() !== 200) {
Logger.log("Error exporting Sheet to PDF! Response Code: " + response.getResponseCode());
return;
}
var blob = response.getBlob();
var timestamp = new Date().toISOString();
// set name to spreadsheet_sheet_range_timestamp.pdf
blob.setName(spreadsheet.getName() + '_' + sheet.getSheetName() + '_' + exportRange + '_' + timestamp + '.pdf');
var folderId = 'enter your folder ID here';
// Create the PDF file in the specific folder
DriveApp.getFolderById(folderId).createFile(blob);
}
}
Note:
For more url parameters, see reference below.
This needs to be an installable trigger, not a simple one.
Output:
References:
Url parameters
Alan Well's answer
Related
I found a script here that does everything I want however for some reason it is splitting the document into several pdf's. I would like to keep everything as it is however just create one single pdf.
Edit: My Google sheets have 5 worksheets and each worksheet at the moment becomes a seperate pdf so I end up with 5 different pdfs. I would like it to just come out as 1 pdf with 5 pages inside.
function savePDFs( optSSId, optSheetId ) {
var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
var url = ss.getUrl().replace(/edit$/,'');
var parents = DriveApp.getFileById(ss.getId()).getParents();
var folders = DriveApp.getFoldersByName('Invoices'); // Modified
var folder = folders.hasNext() ? folders.next() : parents.next(); // Modified
var sheets = ss.getSheets();
for (var i=0; i<sheets.length; i++) {
var sheet = sheets[i];
if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&gid=' + sheet.getSheetId() //the sheet's Id
// following parameters are optional...
+ '&size=letter' // paper size
+ '&portrait=true' // orientation, false for landscape
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false' //hide optional headers and footers
+ '&gridlines=false' // hide gridlines
+ '&fzr=false'; // do not repeat row headers (frozen rows) on each page
var options = {headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()}}
var response = UrlFetchApp.fetch(url + url_ext, options);
var valor = sheet.getRange('D5').getValue(); // Modified
var blob = response.getBlob().setName(valor + '.pdf');
folder.createFile(blob);
}
}
The reason you are getting 5 PDF files is that, you are iterating between each page of the sheet and creating a PDF from there; instead of calling the entire sheet. I ran a test with the following code, and it exported the Google sheet as a 1 PDF.
Note: I made some changes to the first part of the code since I didn't have access to the other functions been call.
I remove this part:
var sheets = ss.getSheets();
for (var i=0; i<sheets.length; i++) {
var sheet = sheets[i];
if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&gid=' + sheet.getSheetId() //the sheet's Id
+ '&size=letter' // paper size
And modify it like this:
// I didn't have access to the optSSId or optSheetId so for my test I added the URL and the active sheet link to the apps script
// you can keep this part as you had it before
var url = "https://docs.google.com/spreadsheets/d/<spreadsheet_ID>/";
var sheet = SpreadsheetApp.getActiveSpreadsheet();
// From the URL_ext I remove + '&gid=' + sheet.getSheetId() since we want the complete sheet
var url_ext = '/export?exportFormat=pdf&format=pdf' //export as pdf
+ '&size=letter' // paper size
So basically you form this URL:
https://docs.google.com/spreadsheets/d/<SPREADSHEETID>//export?exportFormat=pdf&format=pdf&size=letter&portrait=true&fitw=true&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=false&fzr=false
Update:
function savePDFs( optSSId, optSheetId ) {
//var ss = (optSSId) ? SpreadsheetApp.openById(optSSId) : SpreadsheetApp.getActiveSpreadsheet();
//var url = ss.getUrl().replace(/edit$/,'');
//var parents = DriveApp.getFileById(ss.getId()).getParents();
var url = "https://docs.google.com/spreadsheets/d/<Sheet_ID>/";
var folders = DriveApp.getFolderById("<Folder_ID>"); // Modified
//var folder = folders.hasNext() ? folders.next() : parents.next(); // Modified
// I didn't have access to the optSSId or optSheetId so my test I added the URL and the active sheet link to the apps script
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&size=letter' // paper size
+ '&portrait=true' // orientation, false for landscape
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false' //hide optional headers and footers
+ '&gridlines=false' // hide gridlines
+ '&fzr=false'; // do not repeat row headers (frozen rows) on each page
var options = {headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()}}
var response = UrlFetchApp.fetch(url + url_ext, options);
// var valor = sheet.getRange('D5').getValue(); // Modified
var blob = response.getBlob().setName("test" + '.pdf');
folders.createFile(blob);
}
Replace <Sheet_ID> with the ID of the Google Sheet and <Folder_ID> with the ID of the folder where the PDF file will be store.
I am currently new to the google sheet script. I'm doing a simple report generator in google sheet using script. I already have a script that saves a generated pdf file to the google drive. In my google sheet there is a cell referenced to the main data source with dropdown data validation selecting the email of the person and will generate the other details (it a reference also based from that email in the same sheet). what I want is, when I run the script to save pdf file, it should automatically generate pdf file for each item in the dropdown validation list. Is this possible? Anyone who know this please.
this is my code that generate pdf file to the drive (i got this also from the net and made some changes)... thank you so much in advance.
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet2 = ss.getSheetByName('ID');
var gdid1 = sheet2.getRange('B1').getValue();
var gdid2 = sheet2.getRange('B4').getValue();
function onOpen() {
var ui = SpreadsheetApp.getUi()
ui.createMenu('ExportGDrive')
.addItem('Export BasicED', 'exportBasicED')
.addItem('Export College', 'exportCollege')
.addToUi()
}
function _exportBasic(blob, fileName, spreadsheet) {
blob = blob.setName(fileName)
var folder = DriveApp.getFolderById(gdid1)
var pdfFile = folder.createFile(blob)
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
function _exportCollege(blob, fileName, spreadsheet) {
blob = blob.setName(fileName)
var folder = DriveApp.getFolderById(gdid2)
var pdfFile = folder.createFile(blob)
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
function exportAsPDF() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var blob = _getAsBlob(spreadsheet.getUrl())
_exportBlob(blob, spreadsheet.getName(), spreadsheet)
}
function _getAsBlob(url, sheet, range) {
var rangeParam = ''
var sheetParam = ''
if (range) {
rangeParam =
'&r1=' + (range.getRow() - 1)
+ '&r2=' + range.getLastRow()
+ '&c1=' + (range.getColumn() - 1)
+ '&c2=' + range.getLastColumn()
}
if (sheet) {
sheetParam = '&gid=' + sheet.getSheetId()
}
// A credit to https://gist.github.com/Spencer-Easton/78f9867a691e549c9c70
// these parameters are reverse-engineered (not officially documented by Google)
// they may break overtime.
var exportUrl = url.replace(/\/edit.*$/, '')
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=LETTER'
+ '&portrait=true'
+ '&fitw=true'
+ '&top_margin=0.75'
+ '&bottom_margin=0.75'
+ '&left_margin=0.7'
+ '&right_margin=0.7'
+ '&sheetnames=false&printtitle=false'
+ '&pagenum=UNDEFINED' // change it to CENTER to print page numbers
+ '&gridlines=FALSE'
+ '&fzr=FALSE'
+ sheetParam
+ rangeParam
Logger.log('exportUrl=' + exportUrl)
var response
var i = 0
for (; i < 5; i += 1) {
response = UrlFetchApp.fetch(exportUrl, {
muteHttpExceptions: true,
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
},
})
if (response.getResponseCode() === 429) {
// printing too fast, retrying
Utilities.sleep(3000)
} else {
break
}
}
if (i === 5) {
throw new Error('Printing failed. Too many sheets to print.')
}
return response.getBlob()
}
function exportCurrentSheetAsPDF() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var currentSheet = SpreadsheetApp.getActiveSheet()
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), currentSheet)
_exportBlob(blob, SpreadsheetApp.getActiveSheet().getRange('B3').getValue(), spreadsheet)
}
function exportBasicED() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet1 = spreadsheet.getSheetByName('Generate-Basic Ed');
var name = sheet1.getRange('B3').getValue();
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), sheet1)
_exportBasic(blob, name, spreadsheet)
}
function exportCollege() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet1 = spreadsheet.getSheetByName('Generate-College');
var name = sheet1.getRange('B3').getValue();
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), sheet1)
_exportCollege(blob, name, spreadsheet)
}
Try
function nextItem() {
var sh = SpreadsheetApp.getActive();
var data = sh.getRange('myValidationList').getValues();
for (var i = 0; i < data.length; i++) {
sh.getRange('A2').setValue(data[i][0]);
SpreadsheetApp.flush();
// here you can call the script to send pdf
Utilities.sleep(1000);
}
};
assuming that myValidationList is the list of valid data, avd A2 the cell in wich the validation applies.
My script is looping through a list, at each index it is saving a sheet in my workbook as a PDF, then saving it to my google drive folder. There are 7 people in the list. The problem is that my script throws a 429 Error after the 6th PDF is exported. I am trying to figure out how to solve this error but I am quite new to google scripting so I need some help in the right direction.
Error Image
function ToPortrait() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('ValidDSM');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('ValidDSM').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('DSM');
var tab = ss.getSheetByName('DSMD');
var url = ss.getUrl().replace(/edit$/,'');
var sheets = ss.getSheets();
var optSheetId = 1123194386;
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
}
}
// Loop through List of 7
for (var i = 0; i < inputs.length; i++){
sheet2.getRange('B3').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(500);
// Loop through all sheets, generating PDF files.
//for (var i=0; i<sheets.length; i++) {
//var sheet = sheets[i];
// If provided a optSheetId, only save it.
// if (optSheetId && optSheetId !== sheet.getSheetId()) continue;
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ '&gid=' + tab.getSheetId() //the sheet's Id
// following parameters are optional...
+ '&size=letter' // paper size
+ '&portrait=false' // orientation, false for landscape
+ '&fitw=true' // fit to width, false for actual size
+ '&sheetnames=false&printtitle=false&pagenumbers=false' //hide optional headers and footers
+ '&gridlines=false' // hide gridlines
+ '&fzr=false'; // do not repeat row headers (frozen rows) on each page
// Get folder containing spreadsheet, for later export
var name = sheet2.getRange('B3').getValue();
var folderID = "1IsffOYYQOHZJKggUzRTntfjmJKN0F6ga"; // Folder id to save in a folder.
var folder = DriveApp.getFolderById(folderID);
var response = UrlFetchApp.fetch(url + url_ext, options)
var blob = response.getBlob().setName(name);
//save the pdf to drive
folder.createFile(blob);
}
}
I expect all 7 PDFs to be exported but only 6 are.
Through trial and error I modified the below line of code to print the range B4:I59. Can someone help me to understand what the code says and/or how do I read it?
Original code
var printRange = '&c1=0' + '&r1=0' + '&c2=7' + '&r2='+row2; // B2:APn
Modified Code
var printRange = '&c1=1' + '&r1=2' + '&c2=9' + '&r2='+row2; // B4:I59
This is my whole code:
//* Print Extentions
function printPdf() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var gid = sheet.getSheetId();
var pdfOpts = '&size=A4&fzr=false&landscape=false&fith=true&gridlines=false&printtitle=false&sheetnames=false&pagenum=UNDEFINED&attachment=false&gid='+gid;
var row2 = 59;
var printRange = '&c1=1' + '&r1=2' + '&c2=9' + '&r2='+row2; // B4:I59
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + pdfOpts + printRange;
var app = UiApp.createApplication().setWidth(200).setHeight(50);
app.setTitle('Print Extentions List');
var link = app.createAnchor('Download PDF', url).setTarget('_new');
app.add(link);
ss.show(app);
}
The code works
In the line:
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + pdfOpts + printRange;
You are defining a URL that will allow you to export the given spreadsheet as a PDF using the specified options. The & symbols separate arguments you are passing into the URL.
This document gives a nice description of the parameters you are using. According to that document:
//r1=Start Row number - 1 row 1 would be 0 , row 15 wold be 14
//c1=Start Column number - 1 column 1 would be 0, column 8 would be 7
//r2=End Row number
//c2=End Column number
I have a Google spreadsheet with multiple tabs. I have a button on each sheet that calls the functions to create and email a pdf of the active sheet. When the sheets (tabs) are in either the first or second position, the pdf that generates is all the sheets instead of just the active sheet. How can I adjust so it only sends the active sheet each time? It appears to me that the issue is with using the Index number and the getSheets() function. Here is the code:
function sendSheetToPdf(){ // this is the function to call
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet(); // it will send the active sheet.
// if you change the number, change it also in the parameters below
var shName = sh.getName()
var shNum = (ss.getActiveSheet().getIndex() - 1)
sendSpreadsheetToPdf(shNum, sh.getRange('I5').getValue(), sh.getRange('F12').getValue(),sh.getRange('I3').getValue(), sh.getRange('B6').getValue());
}
function sendSpreadsheetToPdf(sheetNumber, pdfName, email,subject, htmlbody) {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheetId = spreadsheet.getId()
var sheetId = sheetNumber ? spreadsheet.getSheets()[sheetNumber].getSheetId() : null;
var url_base = spreadsheet.getUrl().replace(/edit$/,'');
var url_ext = 'export?exportFormat=pdf&format=pdf' //export as pdf
+ (sheetId ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId))
// following parameters are optional...
+ '&size=A4' // paper size
+ '&printtitle=false'
+ '&scale=4'
+ '&portrait=false' // orientation, false for landscape
+ '&sheetnames=false'
+ '&pagenumbers=false' //hide optional headers and footers
+ '&gridlines=false' // hide gridlines
+ '&fzr=false'; // do not repeat row headers (frozen rows) on each page
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
}
}
var response = UrlFetchApp.fetch(url_base + url_ext, options);
var blob = response.getBlob().setName(pdfName + '.pdf');
if (email) {
var mailOptions = {
attachments:blob, htmlBody:htmlbody
}
MailApp.sendEmail(
email,
subject+" (" + pdfName +")",
htmlbody,
mailOptions);
MailApp.sendEmail(
Session.getActiveUser().getEmail(),
"FRWD "+subject+" (" + pdfName +")",
htmlbody,
mailOptions);
}
}
Reason of issue:
The reason of your issue is the following 2 lines.
var sheetId = sheetNumber ? spreadsheet.getSheets()[sheetNumber].getSheetId() : null;
+ (sheetId ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId))
By above 2 lines, the following issues occur.
When sheetNumber is 0, sheetId becomes null.
When sheetId is 0 and null, '&id=' + spreadsheetId is used.
When there is the sheet with gid=0 at the index 1 (2nd page), when the active sheet is the index 0 (1st page) or index 1 (2nd page), '&id=' + spreadsheetId is used.
In the ternary operator and if, 0 and null is judged as false. By above issues, a PDF file with all sheets is returned when the active sheet is 1st and 2nd page.
Modification points:
I think that ss.getActiveSheet().getIndex() always has the number of index.
So how about these modifications?
From:
var sheetId = sheetNumber ? spreadsheet.getSheets()[sheetNumber].getSheetId() : null;
and
+ (sheetId ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId))
To:
var sheetId = spreadsheet.getSheets()[sheetNumber].getSheetId();
and
+ sheetId
Note:
If you want to check the variable, how about modifying as follows?
To:
var sheetId = !isNaN(sheetNumber) && sheetNumber >= 0 && sheetNumber < spreadsheet.getSheets().length ? spreadsheet.getSheets()[sheetNumber].getSheetId() : null;
and
+ (sheetId != null ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId))
If this was not what you want, I'm sorry.