63

我正在开发一个电子发票系统,我们的功能之一是生成发票的 PDF 文件并邮寄。我们有多个发票模板,以后会创建更多,所以我们决定使用 HTML 模板,生成 HTML 文档,然后将其转换为 PDF。但是我们面临 wkhtmltopdf 的问题,据我所知(我已经用 Google 搜索了好几天以找到解决方案)我们不能简单地既使用 HTML 作为页眉/页脚,又在其中显示页码。

在错误报告(或此类)(http://code.google.com/p/wkhtmltopdf/issues/detail?id=140)中,我读到使用 JavaScript 可以实现此组合。但是在此页面或其他地方无法找到有关如何执行此操作的其他信息。

当然,强制使用 JavaScript 并不是那么重要,如果使用 wkhtmltopdf 一些 CSS 魔法可以发挥作用,它会像任何其他骇人听闻的解决方案一样棒极了。

谢谢!

4

8 回答 8

89

实际上它比使用代码片段要简单得多。您可以在命令行中添加以下参数:--footer-center [page]/[topage].

就像 Richard 提到的,更多的变量在文档的页脚和页眉部分。

于 2012-11-21T15:49:23.113 回答
44

在其他一些参数中,页码和总页码作为查询参数传递给页脚 HTML,如官方文档中所述:

... [页码] 参数以 GET 方式发送到页眉/页脚 html 文档。

来源:http ://wkhtmltopdf.org/usage/wkhtmltopdf.txt

所以解决方案是使用一点 JS 来检索这些参数并将它们呈现到 HTML 模板中。这是页脚 HTML 的完整工作示例:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <script>
        function substitutePdfVariables() {

            function getParameterByName(name) {
                var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
                return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
            }

            function substitute(name) {
                var value = getParameterByName(name);
                var elements = document.getElementsByClassName(name);

                for (var i = 0; elements && i < elements.length; i++) {
                    elements[i].textContent = value;
                }
            }

            ['frompage', 'topage', 'page', 'webpage', 'section', 'subsection', 'subsubsection']
                .forEach(function(param) {
                    substitute(param);
                });
        }
    </script>
</head>
<body onload="substitutePdfVariables()">
    <p>Page <span class="page"></span> of <span class="topage"></span></p>
</body>
</html>

substitutePdfVariables()在 body 中调用onload。然后,我们从查询字符串中获取每个支持的变量,并将所有元素中的内容替换为匹配的类名。

于 2016-06-14T08:46:23.733 回答
33

要显示页码和总页数,您可以在页脚或页眉代码中使用此 javascript 代码段:

  var pdfInfo = {};
  var x = document.location.search.substring(1).split('&');
  for (var i in x) { var z = x[i].split('=',2); pdfInfo[z[0]] = unescape(z[1]); }
  function getPdfInfo() {
    var page = pdfInfo.page || 1;
    var pageCount = pdfInfo.topage || 1;
    document.getElementById('pdfkit_page_current').textContent = page;
    document.getElementById('pdfkit_page_count').textContent = pageCount;
  }

并使用页面 onload 调用 getPdfInfo

当然 pdfkit_page_current 和 pdfkit_page_count 将是显示数字的两个元素。

这里截取的片段

于 2011-08-24T11:47:58.813 回答
24

从 wkhtmltopdf 文档(http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html)标题“页脚和页眉”下有一个代码片段来实现页码:

<html><head><script>
function subst() {
  var vars={};
  var x=document.location.search.substring(1).split('&');
  for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
  var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
  for(var i in x) {
    var y = document.getElementsByClassName(x[i]);
    for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
  }
}
</script></head><body style="border:0; margin: 0;" onload="subst()">
<table style="border-bottom: 1px solid black; width: 100%">
  <tr>
    <td class="section"></td>
    <td style="text-align:right">
      Page <span class="page"></span> of <span class="topage"></span>
    </td>
  </tr>
</table>
</body></html>

除了页码之外,还有更多可用的变量可以替换用于页眉/页脚。

于 2012-10-25T09:17:45.703 回答
2

安全的方法,即使您使用的是 XHTML(例如,使用 thymeleaf)。与其他解决方案的唯一区别是使用 // 标签。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <script>
        /*<![CDATA[*/
        function subst() {
            var vars = {};
            var query_strings_from_url = document.location.search.substring(1).split('&');
            for (var query_string in query_strings_from_url) {
                if (query_strings_from_url.hasOwnProperty(query_string)) {
                    var temp_var = query_strings_from_url[query_string].split('=', 2);
                    vars[temp_var[0]] = decodeURI(temp_var[1]);
                }
            }
            var css_selector_classes = ['page', 'topage'];
            for (var css_class in css_selector_classes) {
                if (css_selector_classes.hasOwnProperty(css_class)) {
                    var element = document.getElementsByClassName(css_selector_classes[css_class]);
                    for (var j = 0; j < element.length; ++j) {
                        element[j].textContent = vars[css_selector_classes[css_class]];
                    }
                }
            }
        }
        /*]]>*/
    </script>
</head>
<body onload="subst()">
    <div class="page-counter">Page <span class="page"></span> of <span class="topage"></span></div>
</body>

最后说明:如果使用百里香叶,请替换<script><script th:inline="javascript">.

于 2018-01-26T11:28:02.147 回答
2

我的示例显示了如何在特定页面上隐藏一些文本,在这种情况下,它显示了从第 2 页开始的文本

<span id='pageNumber'>{#pageNum}</span>
<span id='pageNumber2' style="float:right; font-size: 10pt; font-family: 'Myriad ProM', MyriadPro;"><strong>${siniestro.numeroReclamo}</strong></span>
<script>
    var elem = document.getElementById('pageNumber');
    document.getElementById("pageNumber").style.display = "none";
       if (parseInt(elem.innerHTML) <= 1) {
           elem.style.display = 'none';
           document.getElementById("pageNumber2").style.display = "none";
       }
</script>
于 2019-11-04T17:56:34.673 回答
0

就在wkhtmltopdf文档中

更新为 0.12.6。

页脚和页眉:
页眉和页脚可以分别通过 --header-* 和 --footer* 参数添加到文档中。在提供给例如 --header-left 的页眉和页脚文本字符串中,将替换以下变量。

  • [page] 替换为当前正在打印的页数
  • [frompage] 替换为要打印的第一页的编号
  • [topage] 替换为要打印的最后一页的编号
  • [webpage] 替换为正在打印的页面的 URL
  • [section] 替换为当前节的名称
  • [小节] 替换为当前小节的名称
  • [日期] 替换为系统本地格式的当前日期
  • [isodate] 替换为 ISO 8601 扩展格式的当前日期
  • [time] 替换为系统本地格式的当前时间
  • [title] 替换为当前页面对象的标题
  • [doctitle] 替换为输出文档的标题
  • [sitepage] 替换为当前正在转换的站点中的页面编号
  • [sitepages] 替换为当前站点中正在转换的页面数

例如,指定 --header-right "Page [page] of [topage]",将生成文本 "Page x of y",其中 x 是当前页的编号,y 是最后一页的编号,出现在文档的左上角。

页眉和页脚也可以随 HTML 文档一起提供。例如,可以指定 --header-html header.html,并在 header.html 中使用以下内容:

<!DOCTYPE html>   
<html>
  <head><script>
    function subst() {
      var vars = {};
      var query_strings_from_url = document.location.search.substring(1).split('&');
      for (var query_string in query_strings_from_url) {
        if (query_strings_from_url.hasOwnProperty(query_string)) {
          var temp_var = query_strings_from_url[query_string].split('=', 2);
          vars[temp_var[0]] = decodeURI(temp_var[1]);
        }
      }
      var css_selector_classes = ['page', 'frompage', 'topage', 'webpage', 'section', 'subsection', 'date', 'isodate', 'time', 'title', 'doctitle', 'sitepage', 'sitepages'];
      for (var css_class in css_selector_classes) {
        if (css_selector_classes.hasOwnProperty(css_class)) {
            var element = document.getElementsByClassName(css_selector_classes[css_class]);
            for (var j = 0; j < element.length; ++j) {
                element[j].textContent = vars[css_selector_classes[css_class]];
            }
        }
      }   
    }
  </script></head>
  <body style="border:0; margin: 0;" onload="subst()">   
    <table style="border-bottom: 1px solid black; width: 100%">
      <tr>
        <td class="section"></td>
        <td style="text-align:right">
          Page <span class="page"></span> of <span class="topage"></span>
        </td>
      </tr>   
    </table>
  </body>
</html>

专家提示

如果您不使用某些信息,例如webpage, section, subsection, subsubsection,那么您应该删除它们。我们正在生成相当大的 PDF,并且在大约 1,000 页时遇到了分段错误。

经过彻底调查后,它归结为删除那些未使用的变量。不,我们可以生成 7,000 多页 PDF 而不会看到分段错误。

于 2021-02-25T13:01:59.183 回答
-2

它应该完成的方式(即,如果 wkhtmltopdf 支持它)将使用适当的 CSS 分页媒体:http ://www.w3.org/TR/css3-gcpm/

我正在研究现在需要什么。

于 2014-01-23T23:55:45.770 回答