微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

格式化 PDF 的 Google Apps 脚本问题

如何解决格式化 PDF 的 Google Apps 脚本问题

我正在使用 GAS 在源电子表格中生成给定工作表的 PDF。 我的做法是首先将给定的工作表复制到我称之为“中间”的新电子表格文件中,设置样式,然后使用 filetoPDF.getAs("application/pdf"); 将其 PDF 格式。

文件被创建,它拥有我想要的一切,除了两个问题:

  • 我已经使用 sheet.getRange(borderRange).setBorder(true,true,true); 对某些范围应用了一些边框,并且它们确实在“中间”文件显示没有问题。但是,它们在 PDF 中消失了。
  • 我已经合并了一些范围集,那里没有问题,但有一个很大的例外,即工作表中最后一个合并的范围在 PDF 中没有显示一个合并的单元格。

我使用的代码如下:

function crearPdf() {
  const ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
  const destFolder = DriveApp.getFileById(ssID).getParents().next();
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getActiveSheet();

  const sourceRange = ws.getRange(1,1,ws.getMaxRows(),ws.getMaxColumns());
  const numFac = ws.getRange("D20");
  const sourceValues = sourceRange.getdisplayValues();
  const dest = SpreadsheetApp.create("temp " + Date());
  const destSheet = dest.getSheets()[0];
  const destRange = destSheet.getRange(1,destSheet.getMaxRows(),destSheet.getMaxColumns());

  destRange.setValues(sourceValues);
  styleSheet(destSheet);

  const destId = dest.getId();
  const filetoPDF = DriveApp.getFileById(destId);
  const fileAsPDF = filetoPDF.getAs("application/pdf");
  const newFile = DriveApp.createFile(fileAsPDF).setName("Factura " + numFac.getValue() + ' - ' + " '21");
  // const fileUrl = newFile.getDownloadUrl();

  newFile.moveto(destFolder);
  // filetoPDF.setTrashed(true);
}

function styleSheet(sheet) {
  // Declaring our constants
  const arrToMerge = ["B24:G24","B25:G25","B26:G26","B40:H40","B20:C20","B21:C21","B22:C22"];
  const arrToBorder = ["B20:D22","B24:H26","G27:H28"];
  const arrToBold = ["B11","B20","B21","B22","B24","B31","B33","B34","B35","B36","G28","H3","H24","H28"];

  // Direct tweaks
  sheet.setHiddenGridlines(true);
  sheet.setColumnWidth(1,15);
  sheet.getDatarange().setFontFamily("Open Sans");
  sheet.getRange("B40").setWrap(true);
  sheet.getRange("B40:B47").setFontSize(9);
  sheet.autoResizeRows(40,1);
  sheet.setColumnWidth(3,54);
  // sheet.setColumnWidth(2,79);
  sheet.setRowHeights(37,3,7);
  // sheet.setRowHeights(40,7,16);
  sheet.getRange("h24").setHorizontalAlignment("right");
  sheet.getRange("B24:H24").setBackground("#666666").setFontColor("white");

  // Loops for multiple ranges tweaks
  for (let range of arrToMerge) {
    sheet.getRange(range).merge();
  }
  for (let cell of arrToBold) {
    sheet.getRange(cell).setFontWeight("bold");
  }
  for (let range of arrToBorder) {
    sheet.getRange(range).setBorder(true,true);
  }
}

我还从原始文件删除了一些单元格以使其更易于理解(并没有真正删除代码中的所有引用,因此如果您看到对看起来为空的单元格的引用不要感到惊讶)

而下图对应:

原始电子表格

enter image description here

中间文件生成文件是因为原始电子表格中有很多工作表)

enter image description here

最终的PDF

enter image description here

最后,link to a public spreadsheet with dummy data

`getAs("application/pdf") 方法是否有一些已知的奇怪行为?有没有办法让它正常工作?

预先感谢您的帮助!

解决方法

而不是使用 getAs() 将工作表导出为 pdf

你可以这样做

  • 创建导出链接 "https://docs.google.com/spreadsheets/d/"+destId+"/export?"
  • 使用@Shootfast
  • 根据响应的 UrlFetchApp.fetch() 创建一个新文件
  • 使用 blob 确保在执行导出为 pdf 之前完成电子表格的格式化。

示例:

function crearPdf() {

  const ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
  const destFolder = DriveApp.getFileById(ssID).getParents().next();
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getActiveSheet();

  const sourceRange = ws.getRange(1,1,ws.getMaxRows(),ws.getMaxColumns());
  const numFac = ws.getRange("D20");
  const sourceValues = sourceRange.getDisplayValues();
  const dest = SpreadsheetApp.create("temp " + Date());
  const destSheet = dest.getSheets()[0];
  const destRange = destSheet.getRange(1,destSheet.getMaxRows(),destSheet.getMaxColumns());

  destRange.setValues(sourceValues);
  SpreadsheetApp.flush();
  styleSheet(destSheet);
  SpreadsheetApp.flush();

  const destId = dest.getId();
  
  
 //  THIS IS NEW
  var token = ScriptApp.getOAuthToken();
  var url = "https://docs.google.com/spreadsheets/d/"+destId+"/export?";

  var url_ext = 'exportFormat=pdf&format=pdf'        // export as pdf / csv / xls / xlsx
  
  // adjust the following parametrers as desired
  
  
  + '&size=letter'                                   // paper size legal / letter / A4
  + '&portrait=true'                                // orientation,false for landscape
  +'&top_margin=0.50'
  +'&bottom_margin=0.50' 
  +'&left_margin=0.50' 
  +'&right_margin=0.50'
  + '&gridlines=false' 
  // other parameters if you need
  /*
  + '&fitw=true&source=labnol'                       // fit to page width,false for actual size
  + '&sheetnames=false&printtitle=false'             // hide optional headers and footers
  + '&pagenumbers=false'                               // hide page numbers 
  + '&fzr=false'                                     // do not repeat row headers (frozen rows) on each page
  + '&gid=';                                         // the sheet's Id
  */

  var response = UrlFetchApp.fetch(url + url_ext,{
    headers: {
     'Authorization': 'Bearer ' +  token
    },muteHttpExceptions:true
  });
  
  const newFile =  DriveApp.createFile(response.getBlob().setName("Factura " + numFac.getValue() + ' - ' + " '21"));
  // const fileUrl = newFile.getDownloadUrl();

  newFile.moveTo(destFolder);
  // fileToPDF.setTrashed(true);
}
,

嗯,事实证明,您使用 Apps 脚本格式化电子表格的顺序很重要,这就是我丢失一些格式的原因。

我设计格式的方式涉及使用多个单元格数组来应用某些调整,例如合并单元格、设置边框、设置粗体等,并使用 for-of 循​​环遍历每个单元格范围。碰巧的是,如果您有其他调整要做,这些 for-of 循​​环似乎必须是您要做的第一件事,否则它们似乎不起作用。

感谢大家的帮助!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。