Apps Script save as pdf doesn't include drawings and images - pdf

I want to save a Google Doc file as a pdf in the same Google Drive folder as my current file. I know I can download the file as a pdf, but then I have to upload it into the same Google Drive folder. I am trying to skip the upload step.
I have created a script to accomplish all of this, but I cannot get the images and drawings to be included in the resulting pdf.
Here is my code:
function onOpen() {
// Add a custom menu to the spreadsheet.
var ui = DocumentApp.getUi();
var menu = ui.createAddonMenu();
menu.addItem('Save As PDF','saveToPDF')
.addToUi();
}
function saveToPDF(){
var currentDocument = DocumentApp.getActiveDocument();
var parentFolder = DriveApp.getFileById(currentDocument.getId()).getParents();
var folderId = parentFolder.next().getId();
var currentFolder = DriveApp.getFolderById(folderId);
var pdf = currentDocument.getAs('application/PDF');
pdf.setName(currentDocument.getName() + ".pdf");
// Check if the file already exists and add a datecode if it does
var hasFile = DriveApp.getFilesByName(pdf.getName());
if(hasFile.hasNext()){
var d = new Date();
var dateCode = d.getYear()+ "" + ("0" + (d.getMonth() + 1)).slice(-2) + "" + ("0" + (d.getDate())).slice(-2);
pdf.setName(currentDocument.getName() + "_" + dateCode +".pdf");
}
// Create the file (puts it in the root folder)
var file = DriveApp.createFile(pdf);
// Add to source document original folder
currentFolder.addFile(file);
// Remove the new file from the root folder
DriveApp.getRootFolder().removeFile(file);
}
Is there another way to create the pdf, save to the current Google Drive folder, and not lose the images?
UPDATE
I just tested and realized that even if I export as a pdf, the images and drawings aren't included. There has to be a way to do this.
UPDATE 2
I have been testing some more and have learned a few things:
Images in the header/footer are included if they are In line, but if I use Wrap text or Break text they are not.
Images in the body can be any of the three
However, if I use the "Project Proposal" template, they include an image in the footer with Break text and it exports to pdf. I can't tell why their image is any different.
I don't want to use In line because I want the image to touch both sides of the page and In line will always leave at least 1 pixel to the left of the image.

Related

How to download single sheet as PDF to my local device directly (not export to Google Drive)?

I've come across a few scripts to use with Google Sheets that will let me export a single sheet to a file on my Google Drive. However, instead of sending it there, I want it to download to my computer directly.
I'm looking to replace this...
DriveApp.createFile()
with something else that will send the file, with a customized name, as a file to download in my browser.
You want to download a specific sheet in the active Spreadsheet as a PDF file.
If my understanding is correct, how about this sample script? This sample script supposes the following points.
Script is the container-bound script of Spreadsheet.
Sheet you want to download is in the active Spreadsheet.
When the script is run, a dialog is opened. When the button is clicked, the active sheet is downloaded as a PDF file to the local PC.
In this script, the PDF file is downloaded by Javascript. So I used a dialog to execute Javascript.
Sample script:
When you use this script, please copy and paste this script to the script editor. Script is the container-bound script of Spreadsheet. When you run downloadSheetAsPDF(), a dialog is opened on the Spreadsheet. Please check it. When you click the button, the PDF file is downloaded.
function downloadSheetAsPDF() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetId = ss.getActiveSheet().getSheetId();
var url = "https://docs.google.com/a/mydomain.org/spreadsheets/d/" + ss.getId() + "/export?exportFormat=pdf&gid=" + sheetId + "&access_token=" + ScriptApp.getOAuthToken();
var str = '<input type="button" value="Download" onClick="location.href=\'' + url + '\'" >';
var html = HtmlService.createHtmlOutput(str);
SpreadsheetApp.getUi().showModalDialog(html, "sample");
}
Note:
This is a simple sample script. So please modify this for your situation.
If you want to download the specific sheet name, please modify to var sheetId = ss.getSheetByName("sheetName").getSheetId();.
References:
Class HtmlService
Class Ui
If this was not the result you want, I apologize.
Edit:
You want to use the specific filename of PDF file, when the file is downloaded.
You want to automatically download when the script is run.
If my understanding is correct, how about this sample script? The flow of this sample script is as follows. I think that there might be several answers for your situation. So please think of this as just one of several answers.
PDF file is created as a temporal file.
Create the URL for downloading.
Open a dialog box and the PDF file is automatically downloaded by running Javascript.
Remove the temporary file.
Close the dialog box.
Sample script:
function downloadSheetAsPDF2() {
var filename = "sampleFilename.pdf"; // Please set the filename here.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetId = ss.getActiveSheet().getSheetId();
// Creat PDF file as a temporary file and create URL for downloading.
var url = "https://docs.google.com/a/mydomain.org/spreadsheets/d/" + ss.getId() + "/export?exportFormat=pdf&gid=" + sheetId + "&access_token=" + ScriptApp.getOAuthToken();
var blob = UrlFetchApp.fetch(url).getBlob().setName(filename);
var file = DriveApp.createFile(blob);
var dlUrl = "https://drive.google.com/uc?export=download&id=" + file.getId();
// Open a dialog and run Javascript for downloading the file.
var str = '<script>window.location.href="' + dlUrl + '"</script>';
var html = HtmlService.createHtmlOutput(str);
SpreadsheetApp.getUi().showModalDialog(html, "sample");
file.setTrashed(true);
// This is used for closing the dialog.
Utilities.sleep(3000);
var closeHtml = HtmlService.createHtmlOutput("<script>google.script.host.close()</script>");
SpreadsheetApp.getUi().showModalDialog(closeHtml, "sample");
}
Alternatively, You can use the anchor tag to download to local drive with a custom name:
Flow:
Create custom download url for pdf export from using spreadsheet id
UrlFetchApp to fetch the pdf
Serve pdf as Data URI using anchor tag
Use anchor tag's download attribute to provide the custom name for the download
Snippet:
function downloadPdfToDesktop() {
var ss = SpreadsheetApp.getActive(),
id = ss.getId(),
sht = ss.getActiveSheet(),
shtId = sht.getSheetId(),
url =
'https://docs.google.com/spreadsheets/d/' +
id +
'/export' +
'?format=pdf&gid=' +
shtId;
var val = 'PDFNAME';//custom pdf name here
val += '.pdf';
//can't download with a different filename directly from server
//download and remove content-disposition header and serve as a dataURI
//Use anchor tag's download attribute to provide a custom filename
var res = UrlFetchApp.fetch(url, {
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
});
SpreadsheetApp.getUi().showModelessDialog(
HtmlService.createHtmlOutput(
'<a target ="_blank" download="' +
val +
'" href = "data:application/pdf;base64,' +
Utilities.base64Encode(res.getContent()) +
'">Click here</a> to download, if download did not start automatically' +
'<script> \
var a = document.querySelector("a"); \
a.addEventListener("click",()=>{setTimeout(google.script.host.close,10)}); \
a.click(); \
</script>'
).setHeight(50),
'Downloading PDF..'
);
}

creating a PDF via google apps script but creates the PDF with an additional blank page

I have a apps script bound to a spreadsheet that creates a pdf file from the sheet. this creates one single page pdf and saves it in a folder in drive. Up until recently, this worked perfectly. Now every time I run the code it does what it is supposed to but the file has a second page that is blank. When I create the pdf manually via file/download as/pdf doc, it creates the pdf as it should, with only one page. I have tried this with both the original and copy that the script temporarily creates. Both work when done manually. I am looking for some suggestions on what could have gone wrong and what to change. Here is an example of the code:
function makePDF() {
var sheet1 = SpreadsheetApp.getActive().getSheetByName('eTimesheet');
var sheet2 = SpreadsheetApp.getActive().getSheetByName('Time Sheet');
var sheet3 = SpreadsheetApp.getActive().getSheetByName('Data');
var triggercell3 = sheet1.getRange('M33').getValue();
if (triggercell3 == 'GO'){
var techNumber = sheet3.getRange('B5').getValue();
var date = sheet3.getRange('B3').getValue();
var fileID = sheet3.getRange('B7').getValue();
var pdfName = "TimeSheet- "+ techNumber + " " + date
var ss = SpreadsheetApp.getActive();
var folder = DriveApp.getFolderById(fileID);
sheet2.showSheet();
sheet1.hideSheet();
//Copy whole spreadsheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(ss.getId()).makeCopy("tmp_convert_to_pdf", folder))
//save to pdf
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
sheet1.showSheet();
sheet2.hideSheet();
sheet1.getRange('M33').clearContent();
}
}
thanks for any assistance...
Without an example, first question I have is... if you delete a few rows from the sheet and run the script, are you back to 1 page?
I am asking in case the issue is just margin settings. If this is the issue, maybe you can adjust rows or use the UrlFetchApp.fetch approach as PDF page formatting can be specified (eg: margin size).

Mass export all images as individual JPEGs in InDesign?

I am new to Indesign. I have a file that contains images with Photoshop clipping paths. I want to export all the clipped images in a folder. I have tried doing the "Copy Links To" and it successfully exported the original images. However, I do not want the original images but the clipped images instead. Is there a way for me to export all the clipped images as JPEG and not the original linked image? In short, I want to export the images without their background. I hope I'm making sense. I have about 800-1000 images so a batch processing method would be highly appreciated.
I found this script from one of the posts here and modified it a bit to suit my needs. It appears to work in most of my INDD documents, but it fails in others. I wonder why. I sometimes get the error message that
Error string: null is not an object
Source: fileName = File ( rect.graphics[0].itemLink.filePath ).name;
I also noticed that it skips some objects and won't download all of the images. I guess it skips those that are not in rectangles.
test();
function test()
{
var myDoc = app.activeDocument,
apis = myDoc.allPageItems, rect, fileName;
while ( rect = apis.pop() )
{
if ( !(rect instanceof Rectangle) || !rect.graphics[0].isValid ){ continue;}
fileName = File ( rect.graphics[0].itemLink.filePath ).name;
fileName = fileName.replace( /\.[a-z]{2,4}$/i, '.jpg' );
app.jpegExportPreferences.exportResolution = 2400;
app.jpegExportPreferences.jpegQuality = JPEGOptionsQuality.MAXIMUM;
//give it a unique name
var myFile = new File ("C:/Users/RANFacistol-Mata/Desktop/Image Trial/"+ fileName);
rect.exportFile(ExportFormat.JPG, myFile);
}
}
Is there a way for me to modify this script such that instead of iterating through all the rectangles, I would iterate through all of the objects instead, much like clicking this next button
And then check if that object contains an image (jpg, tiff, psd, ai, eps). If it does, then I will export it as scripted above.
Thank you for your help!
You can traverse the links present inside the document with the following snippet, this will take less time as taken by the snippet above...
You can also get the type of link ('eps' or ' pdf' etc) with linkType attribute and filePath with 'filePath' attribute of each link object..
var theDoc = app.documents.item(0);
var theLinkLen = theDoc.links.length;
for(var i = 0; i < theLinkLen; ++i)
{
var link = theDoc.links.item(i);
alert("link name \"" + link.name + "\"" + " has type \"" + link.linkType + "\""+ " with filePath \"" + link.filePath + "\"");
}

How to Download PDF Links in Column and Save to Common Folder

We have a column that contains links to PDFs that starts on line 4 (e.g B4:B). I am trying to find a way to automatically download the PDF files that are accessed via the links to a folder on Drive. This is what I have so far:
function savePDFs() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 3; i < data.length; i++) {
Logger.log(data[i][1]);
}
}
Presumably the above code would write the links starting in column B (index value of [1]) on row 4 (i value of 3) (ie., B4) until the bottom of the data set (eg., data.length()).
I'm now confused about how to access and save the PDF link that are written in the logger to a folder.
Would someone be willing to help me out? I'm currently having to go to each link, click Save Link As... and then navigate to the folder that I'd like to save the linked PDF to. My hope is to modify the above process using code.
Update: I found this bit of code here that may help me out. Note, I changed the PDF link to a currently valid PDF link.
var urlOfThePdf = 'http://download.p4c.philips.com/l4b/9/929000277411_eu/929000277411_eu_pss_aenaa.pdf';// an example of online pdf file
var folderName = 'GAS';// an example of folder name
function saveInDriveFolder(){
var folder = DocsList.getFolder(folderName);// get the folder
var file = UrlFetchApp.fetch(urlOfThePdf); // get the file content as blob
folder.createFile(file);//create the file directly in the folder
}
Okay, I'm going to go and noodle with the data that is in the logger to confirm that the data is in properly formatted PDF links, then I'm going to test this new bit of code out. I feel like I'm getting close.
You can't force a download of a file from an apps script, you must try that from an HTMLService and not sure it will work.
For your need I would recommend to create a dedicated folder and you add all the pdf in it and you use the download function of the drive interface to download all files in one clic.
In drive, a file can be put in several folders so the pdf files stay in the original folder but you create a new folder 'PDF for download" for example and you put them in it. To do that from drive interface you have to click on "shift"+Z when file(s) is/are selected.
For you current list of file you just have to add in your loop the add to folder function. You can use this function.
function addFileToFolder(id){
var folderPDF = DriveApp.getFolderById("Id OFFolder to put pdf");
var file = DriveApp.getFileById(id);
folderPDF.addFile(file);
}
EDIT : Function will browse list of url, get the file and make a copy in a dedicated folder on the user drive.
function downloadInDriveFolder(){
var folderID = 'Id of the folder';// put id of the folder
var folder = DriveApp.getFolderById(folderID)// get the folder
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 3; i < data.length; i++) {
var blob = UrlFetchApp.fetch(data[i][1]).getContent();
var pdf = DriveApp.createFile(blob);
pdf.setName(data[i][0]);//Put as name of the file the value in col A
folder.addFile(pdf);
}
}
Well I figured it out. I was expecting more code, but this does it for me:
function listPDFs() {
var out = new Array();
var row = 3; //row index of 0 = row 1
var column = 4; // column index of 0 = column A
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var folder = DriveApp.getFolderById("this is where you paste your folder id"); // destination folder (this is the 0978SDFSDFKJHSDF078Y98hkyo looking value when you right click your folder and select "Get Link")
for (var i=row ; i<data.length ; i++) {
if(data[i][column] !== "") {
var file = UrlFetchApp.fetch(data[i][column]);
folder.createFile(file);
}
}
return
}
As you can see, I included a row and column variable so that I could easily change these.
I haven't figured out how to assemble them into a merged PDF, but I did figure out that I could sort them by date (which places the top most item first) and then right click and select "Open With...PDF Mergy", which then moves the PDFs into PDF Mergy and merges them up in the correct order. You can find PDF Mergy in the Chrome App Store. If I figure out how to automatically call PDF Mergy from GAS, I'll post that up--but for the time being the above code has saved us a ton of time...so I'm calling it good enough for the time being.

How do I convert multiple .pdf files to .ai files all at once?

As a part of my job, my boss wants me to convert thousands of .pdfs into .ai format in Illustrator CS6 without having to open each individual file (among the thousands) and save each pdf as a .ai. I need to convert these files by the thousands with a few simple steps.
Using Illustrator CS6, I have tried to do this by using the batch option by applying the same action to multiple files, (2). I have chosen two folders for input and output. A source from which I get the pdfs and a destination for the converted .pdfs in .ai format are placed.
While the conversions are successful, the multiple files, in this case 2, opened up individually in Illustrator, I had to save them rudimentarily.
This is not what I need. I need to be able to automatically convert thousands of pdfs into .ai's, without having to open and save each and every one of them.
How do I do this?
You can use this script as starting point. It works for singlepage .pdf files right away. For multipage files you will have to tweak it a bit more
(function(thisObj){
main();
function main(){
var pdffiles = File.openDialog ('select one or more pdf files', '*.pdf', true);
if(pdffiles === null){
return;
}
for(var f = 0; f < pdffiles.length;f++){
var pdf = pdffiles[f];
//~ alert(pdf);
var doc = app.open (pdf);
var namepattern = pdf.path + "/" + pdf.name + ".converted.ai";
var newai = null;
if(!(File(namepattern).exists)){
newai = new File(namepattern);
}else{
newai = File(namepattern);
}
doc.saveAs(newai);
doc.close (SaveOptions.DONOTSAVECHANGES);
}
}
})(this);