Export Google Sheets to PDF without cell gridlines - google-apps-script

I'm trying to export PDF from Google Sheets via Apps Script. I've found useful code online, which works perfectly, except I can't find a way to export it without the grid, or change margins and page size.
function generatePdf() {
var originalSpreadsheet = SpreadsheetApp.getActive();
var sourcesheet = originalSpreadsheet.getSheetByName("TestSheet");
var sourcerange = sourcesheet.getRange('B1:K55'); // range to get - here I get all of columns which i want
var sourcevalues = sourcerange.getValues();
var data = sourcesheet.getDataRange().getValues();
var number = originalSpreadsheet.getRange('G9:H9').getValue();
var newSpreadsheet = SpreadsheetApp.create("Invoice pdf"); // can give any name.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sourcesheet.copyTo(newSpreadsheet);
var destrange = sheet.getRange('B1:K55');
destrange.setValues(sourcevalues);
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
var invoiceName = "Invoice "+number;
var pdf = DriveApp.getFileById(newSpreadsheet.getId());
var theBlob = pdf.getBlob().getAs('application/pdf').setName(invoiceName);
var folderID = "1Y7n1e_tzQWvzVykHJf_DSm9lBVmokDHA"; // Folder id to save in a folder.
var folder = DriveApp.getFolderById(folderID);
var newFile = folder.createFile(theBlob);
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
}
I've been looking for answers everywhere, but I cannot apply some of the solutions I find to my code.

I'm not sure how to do it with the code, but if you want to do it without code... when downloading from Google Sheets, you have the option to remove the cell gridlines. Here are the directions:
File > Download > PDF Document (.pdf)
This will open a preview screen. Sidebar on the right has a dropdown menu called "Formatting."
Under "Formatting," uncheck the box labeled "Show gridlines."
Thats it!

It’s not possible to pass options into the getAs function, but you can export the file yourself and download the URL:
function getPdf(spreadsheet) {
var options = {
format: 'pdf',
exportFormat: 'pdf',
size: 7, // A4
portrait: true,
gridlines: false,
};
// construct export URL
var query = Object.keys(options).map(function (key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(options[key]);
}).join('&');
var exportUrl = spreadsheet.getUrl().replace(/\/edit.*$/, '/export?' + query);
var response = UrlFetchApp.fetch(exportUrl, {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
},
});
return {
fileName: spreadsheet.getName() + '.pdf',
content: response.getBlob().getBytes(),
mimeType: MimeType.PDF,
};
}
The full list of export options can be found at https://stackoverflow.com/a/46312255.

Related

Google Apps Script Drive.file.insert question

I wrote a simple Google Apps Script to select an Excel file, convert it to Google Sheets via Blob, and then copy some cells from that to another Google Sheet. It doesn't work. 3 Questions:
Does Drive.Files.insert return a file object? I get an error saying
source.getSheetByName() is not a function right after setting source
to a Drive.Files.insert. (See below)
Whenever I try to put breakpoints in this section of code, they never break there, even though the code runs. How do I use the debugger/breakpoints here?
How would I specify a different location for the created Google Sheet ?
Thanks!
function convertExceltoGoogleSpreadsheet(e) {
var blob = Utilities.newBlob(e.bytes, e.mimeType, e.filename);
var excelFile = DriveApp.createFile(blob);
var fileName = e.filename;
var excelFile = DriveApp.getFilesByName(fileName).next();
var fileId = excelFile.getId();
var folderId = Drive.Files.get(fileId).parents[0].id;
var blob = excelFile.getBlob();
var resource = {
title: excelFile.getName(),
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{id: folderId}],
};
var source = Drive.Files.insert(resource, blob);
var sourceSheet = source.getSheetByName('Sheet1');
var target = SpreadsheetApp.getActiveSpreadsheet();
var targetSheet = target.getSheetByName("Sheet10");
Logger.log("The values are " + sourceSheet.getRange(1, 1, 10, 1).getValues());
Logger.log("The values are " + targetSheet.getRange(1, 1, 10, 1).getValues());
var targetrange = targetSheet.getRange(1, 1, 3, 5); //sourceSheet.getLastColumn());
var rangeValues = sourceSheet.getRange(1,1, 3,5).getValues(); //sourceSheet.getLastRow()-3, sourceSheet.getLastColumn()).getValues();
targetrange.setValues(rangeValues);
}

Get specific Range to Export

can anyone help me with my problem?
Need to export a specific range (A1:J39), not the full sheet.
function SavePDFtoDrive() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ltrsht = ss.getSheetByName("Schichtübergabe-Protokoll");
var datasheet = ss.getSheetByName("Daten");
var sheets=SpreadsheetApp.getActiveSpreadsheet().getSheets();
for(var i =0;i<sheets.length;i++){
if(sheets[i].getName()!="Schichtübergabe-Protokoll"){ sheets[i].hideSheet() }
}
var pdf = DriveApp.getFileById(ss.getId());
var theBlob = pdf.getBlob().getAs('application/pdf').setName(datasheet.getRange("I8").getValue()+".pdf");
var folderID = "1dyKFNvQWrSiNFA8N5PyUMPJQpWSVhsLf"; // Folder id to save in a folder
var folder = DriveApp.getFolderById(folderID);
var newFile = folder.createFile(theBlob);
}
Answer:
Rather than getting your blob using DriveApp, you can obtain your blob from an export URL using UrlFetchApp.
More Information:
When you use DriveApp to create a blob of a file, it doesn't have the functionality to read the specifics of the file. In this case, you can't specify the range of a Sheet you wish to export with DriveApp.
You can, however, build a URL with all your export parameters and create your export in Drive by creating a blob of the response and creating it in Drive.
Code:
function SavePDFtoDrive() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ltrsht = ss.getSheetByName("Schichtübergabe-Protokoll");
var datasheet = ss.getSheetByName("Daten");
// build your URL:
var url = "https://docs.google.com/spreadsheets/d/" + ss.getId() + "/export?"
//define your parameters:
var params = 'exportFormat=pdf&format=pdf'
+ '&portrait=false'
+ '&fitw=true'
+ '&gid=' + ltrsht.getSheetId()
+ '&range=A1:J39';
//get token for UrlFetch:
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + params, {
'headers': {
'Authorization': 'Bearer ' + token
}
});
var fileName = datasheet.getRange("I8").getValue() + ".pdf";
var theBlob = response.getBlob().setName(fileName);
var folderID = "1Hp-P1dzWaKHhhS2FTPzKib6pwJibS12t";
var folder = DriveApp.getFolderById(folderID);
folder.createFile(theBlob);
}
References:
Class UrlFetchApp | Apps Script | Google Developers
Related Questions/Answers:
how to print a long Google sheets column in fewer columns

Saving as PDF with images and in landscape [duplicate]

This question already has an answer here:
Creating PDF in Landscape (Google Apps Script)
(1 answer)
Closed 3 months ago.
I have a code that, upon a submission from a linked form, will select the row with the most recently submitted information, which auto-fills another sheet in the format I prefer and then saves that as a PDF. I have used this code for several worksheets but now I have need of it on a sheet that contains an image. My PDF is saving without the image, which is essential to the process. In addition to this, I would also like it to save in landscape if someone could help with that, I'd appreciate it.
I've played around with the code a bit, but I had help with writing it and don't understand the language enough to make this work.
function generatePdf() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheeta = ss.getSheetByName('Firstsheet');
sheeta.getRange("A2:A").clear();
var lastrow = sheeta.getLastRow();
var range = sheeta.getRange(lastrow, 1);
var values = range.setValue("autofill"); //This is a checkbox in column A which triggers the vlookup on the second sheet
var originalSpreadsheet = SpreadsheetApp.getActive();
var sourcesheet = originalSpreadsheet.getSheetByName("Secondsheet");
var sourcerange = sourcesheet.getRange('A:I');
var sourcevalues = sourcerange.getValues();
var data = sourcesheet.getDataRange().getValues();
var pdfname = sourcesheet.getRange('E34').getDisplayValue();
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sourcesheet.copyTo(newSpreadsheet);
var destrange = sheet.getRange('A:I');
destrange.setValues(sourcevalues);
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
var pdf = DriveApp.getFileById(newSpreadsheet.getId());
var theBlob = pdf.getBlob().getAs('application/pdf').setName("Sheet" + pdfname);
var folderID = "folder ID goes here";
var folder = DriveApp.getFolderById(folderID);
var newFile = folder.createFile(theBlob);
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
sheeta.getRange("A2:A").clear();
}
I need the image in A1:F29 (merged) to save into the intermediary sheet that this formula creates to then save to the PDF. It would also be nice to save in landscape if at all possible.
1) The problem with the missing image is that you’re making the copy process twice, the first one using copyTo() function which copy the all sheet correctly. And then a second one where you use:
var destrange = sheet.getRange('A:I');
destrange.setValues(sourcevalues);
Which copy all the data, even “over the cell” images but not “in cell” images (probably because this is a new Sheets feature), which probably is the problem you’re facing. So you should delete those 2 lines of code in order to not override the first copy process. That’s what i did and worked fine.
2) As there is no option to specify the landscape feature, you can use the method they used in the link provided by #cooper [1] making a request to the export Url. I implemented the code and worked as intended, you just have to erase these 2 lines:
var pdf = DriveApp.getFileById(newSpreadsheet.getId());
var theBlob = pdf.getBlob().getAs('application/pdf').setName("Sheet" + pdfname);
For this:
var url = newSpreadsheet.getUrl();
//remove the trailing 'edit' from the url
url = url.replace(/edit$/, '');
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' + //export as pdf
//below parameters are optional...
'&portrait=false' + //orientation, false for landscape
'&gid=' + newSpreadsheet.getSheetId(); //the sheet's Id
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var theBlob = response.getBlob().setName("Sheet" + pdfname);
[1] https://ctrlq.org/code/19869-email-google-spreadsheets-pdf

Google Apps Script - Using URL of File in Drive in =IMAGE() Spreadsheet Formula

In the below code, I'm getting the URL of a file in my Drive and using that in the formula =IMAGE(). However, the image isn't being displayed in the cell. I copied and pasted the URL that was being retrieved into my browser and it pulls up the image file. I also tried entering a different URL (from a Google image search) and it displayed the image in the cell. Here is a snippet of my code that isn't working:
//Function to populate Packing Instructions sheet
function createPackingInstructions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entryFormSheet = ss.getSheetByName('Entry Form');
var packingInstructionsSheet = ss.getSheetByName('Packing Instructions');
var poNumber = entryFormSheet.getRange(2, 2).getValue();
var drive = DriveApp;
var proofHorizontal = drive.getFilesByName('PO ' + poNumber + ' Proof Horizontal.png');
var proofRange = packingInstructionsSheet.getRange(1, 7);
Logger.log(poNumber);
//Starts by clearing the Instructions sheet
packingInstructionsSheet.getRange(11, 1, 30, 11).clear();
proofRange.clearContent();
Logger.log(proofHorizontal.hasNext());
//Gets image file URL
while (proofHorizontal.hasNext()) {
var file = proofHorizontal.next();
var proofName = file.getName();
var proofUrl = file.getUrl();
Logger.log(proofName);
Logger.log(proofUrl);
proofRange.setFormula('IMAGE("' + proofUrl + '", 1)');
}
}
I adjusted the code based on the advice in here to use the permalink version of the URL, but it has the same behavior; it inputs the formula correctly and the URL works when entered into my browser, but the image won't display in the cell. Here is the updated code:
//Function to populate Packing Instructions sheet
function createPackingInstructions() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entryFormSheet = ss.getSheetByName('Entry Form');
var packingInstructionsSheet = ss.getSheetByName('Packing Instructions');
var poNumber = entryFormSheet.getRange(2, 2).getValue();
var drive = DriveApp;
var proofHorizontal = drive.getFilesByName('PO ' + poNumber + ' Proof Horizontal.png');
var proofRange = packingInstructionsSheet.getRange(1, 7);
var baseUrl = "http://drive.google.com/uc?export=view&id=";
Logger.log(poNumber);
//Starts by clearing the Instructions sheet
packingInstructionsSheet.getRange(11, 1, 30, 11).clear();
proofRange.clearContent();
Logger.log(proofHorizontal.hasNext());
//Gets image file URL
while (proofHorizontal.hasNext()) {
var file = proofHorizontal.next();
//file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
var proofId = file.getId();
var proofUrl = baseUrl+proofId;
Logger.log(proofUrl);
proofRange.setFormula('IMAGE("' + proofUrl + '", 1)');
}
}
Necro-ing my own questions, since I found a working solution:
My second code example above was close, but you need to use the "download" version of the URL, not the "view" version. See below:
var baseUrl = "https://drive.google.com/uc?export=download&id=";
//Gets image file URL
while (proofHorizontal.hasNext()) {
var file = proofHorizontal.next();
//This line may be necessary, depending on permissions
//file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
var proofId = file.getId();
var proofUrl = baseUrl+proofId;
}
Here is a link to some info on this: https://blog.appsevents.com/2014/04/how-to-bypass-google-drive-viewer-and.html

Google script save / update file

I am again creating a simple script to save a daily menu cart. Aim is, that the file (PDF) can be shared with a static link. Base for the PDF is a Google spreadsheet.
Currently I have the following code:
// Add new menu to sheet
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [
{name: "Speichern", functionName: "savepdf"},
];
spreadsheet.addMenu("Als PDF speichern", entries);
};
// Add function to save sheet as PDF
function savepdf () {
// Get spreadsheet file
var fileid = 'FILEIDGOESHERE';
// Create date for file name
var ss = SpreadsheetApp.openById(fileid);
var name = ss.getName();
var sheet = ss.getSheetByName('Tageskarte');
var range = sheet.getRange(12,1);
var d = range.getValue();
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1;
var curr_year = d.getFullYear();
var theDate = curr_year + "-" + curr_month + "-" + curr_date + "-";
var namearchive = "Tageskarte-"+ theDate +".pdf";
var name = "Tageskarte-Allweglehen.pdf";
// Choose folder where PDFs are saved
var foldersave=DriveApp.getFolderById('FOLDERIDGOESHERE');
var foldersavearchive=DriveApp.getFolderById('FOLDERIDGOESHERE');
// OAuth
var request = {
"method": "GET",
"headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
// Create PDF + update current file
var fetch='https://docs.google.com/spreadsheets/d/'+fileid+'/export?format=pdf&size=A4&portrait=true&gridlines=false'
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().getAs('application/pdf').setName(name);
var file = foldersave.createFile(pdf);
// Create PDF for archive and save
var pdfarchive = UrlFetchApp.fetch(fetch, request);
pdfarchive = pdfarchive.getBlob().setName(namearchive);
var file = foldersavearchive.createFile(pdfarchive);
}
/*
fmcmd=12
size=legal/A4
fzr=true/false
portrait=false/true
fitw=true/false
gid=0/1/2
gridlines=false/true
printtitle=false/true
sheetnames=false/true
pagenum=UNDEFINED
attachment=false/true
*/
My problem is the point "Create PDF + update current file. The code is saving a new file with the same name, but than I have of course a new static share link of the menu.
I think I have to use something with the "getblob" function to update the current file.
Would be very good, if anybody would have an idea.
Many thanks.
I was able to find a working solution with Drive.Files.update
// Create PDF + update current file
var fetch='https://docs.google.com/spreadsheets/d/'+fileid+'/export?format=pdf&size=A4&portrait=true&gridlines=false'
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().getAs('application/pdf').setName(name);
var deleteexisting = foldersave.getFilesByName(name);
if (deleteexisting.hasNext() === false) {
// if no file is found then create it
foldersave.createFile(pdf);
} else {
while (deleteexisting.hasNext()) {
var updatedPDF = deleteexisting.next();
Drive.Files.update({mimeType: 'application/pdf'}, updatedPDF.getId(), pdf);
}
}