如何使用wkhtmltopdf在页眉/页脚htmls中进行页码编号?

时间:2011-08-24 11:00:26

标签: javascript css wkhtmltopdf css-paged-media

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

在错误报告(或类似)(http://code.google.com/p/wkhtmltopdf/issues/detail?id=140)中,我通过JavaScript阅读了这个组合可以实现的。但是,没有关于如何做到这一点的其他信息可以在这个页面或其他地方找到。

强制使用JavaScript当然不是那么重要,如果使用wkhtmltopdf,一些CSS魔法可以起作用,那就像任何其他hackish解决方案一样棒。

谢谢!

8 个答案:

答案 0 :(得分:63)

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

与richard一样,其他变量位于the documentation的页脚和标题部分。

答案 1 :(得分:32)

在其他一些参数中,页码和总页码将作为查询参数传递给页脚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()在正文onload中调用。然后,我们从查询字符串中获取每个受支持的变量,并使用匹配的类名替换所有元素中的内容。

答案 2 :(得分:25)

要显示页码和总页数,您可以在页脚或标题代码中使用此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;
  }

使用page onload调用getPdfInfo

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

摘自here

的摘录

答案 3 :(得分:16)

来自wkhtmltopdf文档(http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html)标题“Footers and Headers”下面有一个代码片段来实现页码编号:

<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>

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

答案 4 :(得分: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>

答案 5 :(得分:1)

它应该完成的方式(也就是说,如果wkhtmltopdf支持它)将使用正确的CSS分页媒体:http://www.w3.org/TR/css3-gcpm/

我正在研究它现在需要做些什么。

答案 6 :(得分:1)

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

<!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">

答案 7 :(得分:0)

wkhtmltopdf Docs 开始

更新至 0.12.6。

<块引用>

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

  • [page] 替换为当前正在打印的页数
  • [frompage] 替换为要打印的第一页的编号
  • [topage] 替换为要打印的最后一页的编号
  • [webpage] 替换为正在打印的页面的 URL
  • [section] 替换为当前部分的名称
  • [subsection] 替换为当前小节的名称
  • [date] 替换为系统本地格式的当前日期
  • [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>

专业提示

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

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