【问题标题】:Google apps script getAs('application/pdf') layoutGoogle 应用程序脚本 getAs('application/pdf') 布局
【发布时间】:2017-12-25 20:24:25
【问题描述】:

我正在使用我找到的应用脚本 here 从电子表格生成 PDF 文件。 这个用好旧的 方法 getAs('application/pdf') 效果很好。

问题在于以这种方式生成的 PDF 文档具有不需要的不对称边距(右侧较大,左侧较窄)。我只是想让页面居中。奇怪的是,当我从 Google 菜单文件 -> 打印(或 Ctrl + P)打印时,文档显示正确居中。

我的代码如下所示:

function CreaPDF() {
  //The function prints an invoice to PDF. First it copies spreadsheet to a new document.
  //Deletes all sheet except the one to print. Saves it to PDF. 
  //It overwrites any existing doc with same name.

  var sourceSpreadsheet = SpreadsheetApp.getActive();          
  var sheetName = "Factura";
  var folderID = getParentFolder(); // Folder id to save in a folder.
  var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
  var folder = DriveApp.getFolderById(folderID); 
  var numf = sourceSpreadsheet.getRangeByName("NumeroFactura").getValue();
  var anof = numf.split("/",2);   // Seeks number and year -> filename 

  var pdfName = anof[1] +"_Factura_" + anof[0]+ "_Dra_Salazar"; // Nombre del documento;

  //Copy whole spreadsheet 2 temporary sheet
  var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))

  //delete redundant sheets
  var sheets = destSpreadsheet.getSheets();
  for (i = 0; i < sheets.length; i++) {
    if (sheets[i].getSheetName() != sheetName){
    destSpreadsheet.deleteSheet(sheets[i]);
    }
  }

  //Deletes pdf if already exists
  var files = DriveApp.getFilesByName(pdfName);
  while (files.hasNext()) {
   files.next().setTrashed(true);
   }
  var destSheet = destSpreadsheet.getSheets()[0];
  //repace cell values with text (to avoid broken references)
  var sourceRange = sourceSheet.getRange(1, 1,sourceSheet.getMaxRows(),sourceSheet.getMaxColumns());

  var sourcevalues = sourceRange.getDisplayValues();
  var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
  destRange.setValues(sourcevalues);

  SpreadsheetApp.getActiveSpreadsheet().toast('Creando PDF');

  //save to pdf
  var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
  var newFile = folder.createFile(theBlob);

  //Delete the temporary sheet
  DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
  return true;
}

我打印时的设置是:

  • 纸张尺寸:“A4”
  • 比例:“正常”(我也试过:“适合宽度”和 “适合页面”)
  • 方向:“纵向”
  • 边距:“正常”

正如Google Help Forums 中所见,这似乎是谷歌打印方式的一个老问题。总之,似乎没有保存打印设置,也没有办法将任何参数传递给 getAs('application/pdf') 方法。所以我假设该方法(和菜单打印选项)使用无法修改的默认参数。有什么解决办法吗? “打印或更改页面设置”帮助页面没有太大帮助。

非常感谢

【问题讨论】:

标签: pdf printing google-apps-script


【解决方案1】:

受到科斯的鼓舞。

我使用 chrome 开发者工具跟踪了由 google 电子表格 Download as GUI 创建的请求。当你点击Print settings中的next时,chrome会发送post请求并获取pdf文件。

让我们切入正题。下面是我的代码。

var sourceSpreadsheet = SpreadsheetApp.getActive();
var url = 'https://docs.google.com/spreadsheets/d/' + sourceSpreadsheet.getId() + '/pdf?id=' + sourceSpreadsheet.getId()
var formData = {
    'a': 'false',
    'pc': '[null,null,null, ... SOME VERY LONG LIST OF NULLS AND NUMBERS ... 166]],[[0,5]]]],0]',
    'gf': '[]'
};
var token = ScriptApp.getOAuthToken(); // doesn't needed when sheet is public
var options = {
        'method': 'post',
        'payload': formData,
        'muteHttpExceptions': true,
        headers: {
            'Authorization': 'Bearer ' + token
        }
    };
var response = UrlFetchApp.fetch(url, options)

var theBlob = response.getBlob().setName('YourPDFName.pdf');

您可以通过以下方式填写formData['pc']
1.在Network标签记录请求。
2.点击pdf?id=blahblah pic for step 2
3. 向下滚动找到Form Data pic for step 3
4. 复制表格数据并填写您的代码。

表单数据如下:
[null,null,null,null,null,null,null,null,null,0,[["$Sheet_id"]],10000000,null,null,null,null,null,null,null,null,null,null,null,null,null,null,$day_after_30-12-1899,null,null,[$note,null,1,$note,0,0,0,0,$fixed_row,1,1,1,$headers,$footers,1,1],["A4",1,2,1,[0.75,0.75,0.7,0.7]],null,0,[["$Sheet_id",[[26,52]....],[[0,5]]]],0]
还有更多参数,但我找不到所有参数。参数也可能是错误的,因为我通过检查更改的值找到了它们的值。

当您更改 $day_after_30-12-1899 时,pdf 中打印的日期会更改。

您可以自定义页眉/页脚。它们是 UTF16 编码的,并且有几个控制字符。

| Name in `Download as` GUI | character | 
|---------------------------|-----------|
| page number A             | \uee12    |
| page number B             | \uee15    |
| page number C             | \uee16    |
| Workbook title            | \uee10    |
| sheet name                | \uee11    |


|   meaning in date & time  | character | 
|---------------------------|-----------|
| date formatstr start      | \uee13    |
| year                      | yyyy      |
| month                     | M         |
| day                       | d         |
| date formatstr end        | \uee14    |
|                           |           |
| time formatstr start      | \uee17    |
| am or pm                  | am/pm     |
| hour in 12hour clock      | h         |
| minute                    | mm        |

你可以像这样使用时间和日期YourText\uee13yy. M. d\uee14Yourtext

我建议使用 GUI 创建 formData['pc'] 并修改 $day_after_30-12-1899

*欢迎任何更正。虽然我的母语不是英语,但有很多尴尬/不正确的表达方式。

【讨论】:

  • 如何将它用于我的自定义页脚?对不起,我是 GAS 的菜鸟。我正在尝试找到一种方法,让我的 gsheet 在使用 GAS 导出到 PDF 时显示页脚。当我将$footer 更改为公司地址时,它仍然不会出现在 pdf 中。
【解决方案2】:

试试这个基于https://ctrlq.org/code/19869-email-google-spreadsheets-pdf的解决方案

使用导出 url 参数,您可以为结果 pdf 设置所需的选项。您还可以设置要导出的工作表的特定 ID,因此您不再需要复制整个电子表格。

function CreaPDF() {
  //The function prints an invoice to PDF. First it copies spreadsheet to a new document.
  //Deletes all sheet except the one to print. Saves it to PDF. 
  //It overwrites any existing doc with same name.

  var sourceSpreadsheet = SpreadsheetApp.getActive();          
  var sheetName = "Factura";
  var folderID = getParentFolder(); // Folder id to save in a folder.
  var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
  var folder = DriveApp.getFolderById(folderID); 
  var numf = sourceSpreadsheet.getRangeByName("NumeroFactura").getValue();
  var anof = numf.split("/",2);   // Seeks number and year -> filename 

  var pdfName = anof[1] +"_Factura_" + anof[0]+ "_Dra_Salazar"; // Nombre del documento;

  SpreadsheetApp.getActiveSpreadsheet().toast('Creando PDF');

  // export url
  var url = 'https://docs.google.com/spreadsheets/d/'+sourceSpreadsheet.getId()+'/export?exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
  + '&size=A4'                           // paper size legal / letter / A4
  + '&portrait=true'                     // orientation, false for landscape
  + '&fitw=false'                        // fit to page width, false for actual size
  + '&sheetnames=false&printtitle=false' // hide optional headers and footers
  + '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines
  + '&fzr=false'                         // do not repeat row headers (frozen rows) on each page
  + '&gid='+sourceSheet.getSheetId();    // the sheet's Id

  var token = ScriptApp.getOAuthToken();

  // request export url
  var response = UrlFetchApp.fetch(url, {
    headers: {
      'Authorization': 'Bearer ' +  token
    }
  });

  var theBlob = response.getBlob().setName(pdfName+'.pdf');

  // delete pdf if already exists
  var files = folder.getFilesByName(pdfName);
  while (files.hasNext())
  {
    files.next().setTrashed(true);
  }

  // create pdf
  var newFile = folder.createFile(theBlob);

  return true;
}

【讨论】:

  • 非常感谢您的帮助。似乎没问题...但是,pdf文件应该存储在哪里?我运行代码但找不到结果。有没有办法设置目标文件夹?还是只是父文件夹?
  • 文件创建代码未更改:var newFile = folder.createFile(theBlob); 只是文件源 (theBlob) 现在取自 UrlFetchApp 响应。
  • 好的,经过测试,它可以工作。我的谷歌帐户权限有些问题。很好的解决方案!
  • 除了一个参数:&pagenumbers 外,此方法有效。也就是说,当设置为“真”时,我没有得到页码。我也将其视为 &pagenum,但这对我也不起作用。有关如何获取页码的任何建议?它们与用户界面一起进入页脚。我也无法找到如何让页脚中的其他项目工作:日期/时间戳。我应该将此作为一个单独的问题发布吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-14
  • 2021-04-08
  • 1970-01-01
相关资源
最近更新 更多