Is there a way to print multiple tabs of a spreadsheet (but not all of them) as a single pdf?

拈花ヽ惹草 提交于 2021-01-28 07:55:01

问题


I've done some research but haven't found any way to do this. Tried to do what Andrew Roberts explains here http://www.andrewroberts.net/2017/03/apps-script-create-pdf-multi-sheet-google-sheet/ to convert the spreadsheet (or a specific tab) to pdf:

    function convertSpreadsheetToPdf(email, spreadsheetId, sheetName, pdfName) {

     var spreadsheet = spreadsheetId ? SpreadsheetApp.openById(spreadsheetId) : 
     SpreadsheetApp.getActiveSpreadsheet();
     spreadsheetId = spreadsheetId ? spreadsheetId : spreadsheet.getId()  
     var sheetId = sheetName ? spreadsheet.getSheetByName(sheetName).getSheetId() : null;  
     var pdfName = pdfName ? pdfName : spreadsheet.getName();
     var parents = DriveApp.getFileById(spreadsheetId).getParents();
     var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
     var url_base = spreadsheet.getUrl().replace(/edit$/,'');

     var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf

      // Print either the entire Spreadsheet or the specified sheet if optSheetId is provided
      + (sheetId ? ('&gid=' + sheetId) : ('&id=' + spreadsheetId)) 
      // following parameters are optional...
      + '&size=A4'      // 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

  var options = {
    headers: {
      'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken(),
    }
  }

  var response = UrlFetchApp.fetch(url_base + url_ext, options);
  var blob = response.getBlob().setName(pdfName + '.pdf');
  folder.createFile(blob);

  if (email) {

    var mailOptions = {
      attachments:blob
    }

    MailApp.sendEmail(
      email, 
      "Here is a file named " + pdfName, 
      "Please let me know if you have any questions or comments.", 
      mailOptions);
  }

Looking at the comments, he proposes adding the following code, which I put inside another function:

  function printtwopdfs() {

  var sheetNames = ["Table1,"Table2"]

  sheetNames.forEach(function(sheetName) {
  convertSpreadsheetToPdf(TEST_EMAIL, "xxxxxx", sheetName, 
  "pdfteste")
  })}

But what I got was each sheet printed as one pdf separately.

Hidding all tabs except the ones I want and printing the spreadsheet as a whole isn't an option for me, since it has too many tabs (about 15). Besides that, I'm not likely to copy the selected sheets to a new spreadsheet because the function would take too long to run, unless I can do this very quickly. Any ideas of how to proceed?


回答1:


  • You want to create a PDF file by selecting sheets from the Google Spreadsheet.
    • The Google Spreadsheet has 15 sheets.
    • For example, you want to select 2 sheets of "Table1" and "Table2" and want to create them as one PDF file. Then, the PDF file is sent as an email.
  • You want to reduce the process cost for achieving above.
    • You want to finish to run the script in 20 seconds.
  • You want to achieve this using Google Apps Script.

From your question and replying, I could understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.

In this case, I thought that hiding sheets except for the sheets you want to use might be suitable. For this, here, I would like to propose to hide the sheets using the method of spreadsheets.batchUpdate in Sheets API. Because I thought that in this case, the process cost of Sheets API can be lower than that of Spreadsheet service.

Flow:

The flow of this modified script is as follows.

  1. Hide sheets except for the sheets you want to create as a PDF file.
  2. Create the PDF file from the Spreadsheet.
  3. Show all sheets.

Modified script:

Before you run the script, please enable Sheets API at Advanced Google services. And please set the variables of sheetNames, email and spreadsheetId. And run the function of printtwopdfs().

function convertSpreadsheetToPdf(email, spreadsheetId, pdfName) {
  var spreadsheet = spreadsheetId ? SpreadsheetApp.openById(spreadsheetId) : SpreadsheetApp.getActiveSpreadsheet();
  var spreadsheetId = spreadsheetId ? spreadsheetId : spreadsheet.getId();
  var pdfName = pdfName ? pdfName : spreadsheet.getName();
  var parents = DriveApp.getFileById(spreadsheetId).getParents();
  var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
  var url_base = spreadsheet.getUrl().replace(/edit$/,'');
  var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf
  + '&id=' + spreadsheetId
  + '&size=A4'      // 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
  var options = {headers: {'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken()}}
  var response = UrlFetchApp.fetch(url_base + url_ext, options);
  var blob = response.getBlob().setName(pdfName + '.pdf');
  folder.createFile(blob);
  if (email) {
    var mailOptions = {attachments:blob}
    MailApp.sendEmail(email, "Here is a file named " + pdfName, "Please let me know if you have any questions or comments.", mailOptions);
  }
}

// Please run this function.
function printtwopdfs() {
  var sheetNames = ["Table1", "Table2"];
  var email = "###";  // Please set email address.
  var spreadsheetId = "###";  // Please set Spreadsheet ID.

  // Hide sheets.
  var allSheets = SpreadsheetApp.openById(spreadsheetId).getSheets();
  var hiddenResource = allSheets.map(function(s) {
    var obj = {updateSheetProperties: {properties: {sheetId: s.getSheetId(), hidden: true}, fields: "hidden"}};
    if (sheetNames.indexOf(s.getSheetName()) != -1) obj.updateSheetProperties.properties.hidden = false;
    return obj;
  });
  Sheets.Spreadsheets.batchUpdate({requests: hiddenResource}, spreadsheetId);

  // Create PDF file.
  convertSpreadsheetToPdf(email, spreadsheetId, "pdfteste");

  // Show all sheets.
  var showResource = allSheets.map(function(s) {return {updateSheetProperties: {properties: {sheetId: s.getSheetId(), hidden: false}, fields: "hidden"}}});
  Sheets.Spreadsheets.batchUpdate({requests: showResource}, spreadsheetId);
}

Note:

  • In my environment, when the above script is used for the Google Spreadsheet including 20 sheets which have values in cells, the process time of about 5 seconds was obtained. But I'm not sure whether this can be used for your actual situation. I apologize for this.

References:

  • Advanced Google services
  • Method: spreadsheets.batchUpdate
  • UpdateSheetPropertiesRequest



回答2:


If I understand you correctly:

  • You want to print some but not all sheets in a single PDF.
  • You can do this by hiding the unwanted sheets and printing the full spreadsheet (only unhidden sheets get print).
  • It's uncomfortable to hide and show the unwanted sheets every time you want to print the PDF, specially when there are many sheets.

If the above is correct, then you could use the script to, first, hide the unwanted sheets, then print the PDF, and finally show these unwanted sheets again. It could be done the following way (check inline comments for more detailed information):

function convertSpreadsheetToPdf(email, spreadsheetId, sheetsToPrint) {
  var ss = SpreadsheetApp.openById(spreadsheetId);
  // Get the names of all sheets in the spreadsheet:
  var allSheets = ss.getSheets().map(function(sheet) {
    return sheet.getName();
  });
  // Get the names of the sheets to ignore:
  var sheetsToHide = allSheets.filter(function(sheetName) {
    return sheetsToPrint.indexOf(sheetName) === -1;
  });
  // Hide the sheets to ignore:
  sheetsToHide.forEach(function(sheetName) {
    var sheet = ss.getSheetByName(sheetName);
    sheet.hideSheet();
  })
  var pdfName = ss.getName();
  var parents = DriveApp.getFileById(spreadsheetId).getParents();
  var folder = parents.hasNext() ? parents.next() : DriveApp.getRootFolder();
  var url_base = ss.getUrl().replace(/edit$/,'');  
  var url_ext = 'export?exportFormat=pdf&format=pdf'   //export as pdf  
  // Print either the entire Spreadsheet (only unhidden sheets):
  + '&id=' + spreadsheetId 
  // following parameters are optional...
  + '&size=A4'      // 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
  var options = {
    headers: {
      'Authorization': 'Bearer ' +  ScriptApp.getOAuthToken(),
    }
  }
  var response = UrlFetchApp.fetch(url_base + url_ext, options);
  var blob = response.getBlob().setName(pdfName + '.pdf');
  folder.createFile(blob);
  if (email) {
    var mailOptions = {
      attachments:blob
    }

    MailApp.sendEmail(
      email, 
      "Here is a file named " + pdfName, 
      "Please let me know if you have any questions or comments.", 
      mailOptions);
  }
  // Show the ignored sheets:
  sheetsToHide.forEach(function(sheetName) {
    var sheet = ss.getSheetByName(sheetName);
    sheet.showSheet();
  })    
}

This function accepts the email, the spreadsheetId and an array made of the names of the sheets to print as parameters. A possible call could be like this:

convertSpreadsheetToPdf("your-email@your-domain", "your-spreadsheet-id", ["Sheet1","Sheet2","Sheet5"])

I have simplified this code a bit in order to work on this (the name of the PDF is always the name of the spreadsheet, and you always have to provide the spreadsheet id), but feel free to revert these changes.

Reference:

  • Sheet.hideSheet()
  • Sheet.showSheet()
  • Array.prototype.filter()
  • Array.prototype.indexOf()

I hope this is of any help.



来源:https://stackoverflow.com/questions/60068741/is-there-a-way-to-print-multiple-tabs-of-a-spreadsheet-but-not-all-of-them-as

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!