web-dev-qa-db-fra.com

Comment faire la numérotation de page dans les fichiers HTML d'en-tête/pied de page avec wkhtmltopdf?

Je développe un système de facturation électronique et l'une de nos fonctionnalités est de générer des PDF des factures et de les envoyer par la poste. Nous avons plusieurs modèles pour les factures et nous en créerons d'autres plus tard. Nous avons donc décidé d'utiliser des modèles HTML, de générer un document HTML, puis de le convertir au format PDF. Mais nous sommes confrontés à un problème avec wkhtmltopdf. Autant que je sache (cela fait des jours que nous cherchons Google pour trouver la solution), nous ne pouvons pas simplement utiliser HTML comme en-tête/pied de page et y afficher les numéros de page.

Dans un rapport de bogue (ou autre) ( http://code.google.com/p/wkhtmltopdf/issues/detail?id=140 ) je lisais que javascript permettait de réaliser ce combo. Mais aucune autre information sur la façon de le faire ne peut être trouvée sur cette page ou ailleurs.

Bien sûr, il n’est pas très important de forcer l’utilisation de JavaScript, si avec wkhtmltopdf une magie CSS pouvait fonctionner, elle serait tout aussi géniale que toute autre solution bidon.

Merci!

39
Tamás Barta

Pour afficher le numéro de page et le nombre total de pages, vous pouvez utiliser cet extrait de code javascript dans votre code de pied de page ou en-tête:

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

Et appelez getPdfInfo avec page onload

Bien sûr, pdfkit_page_current et pdfkit_page_count seront les deux éléments affichant les chiffres.

Extrait tiré de ici

21
Dan Mazzini

En réalité, c'est beaucoup plus simple qu'avec l'extrait de code. Vous pouvez ajouter l'argument suivant sur la ligne de commande: --footer-center [page]/[topage].

Comme Richard l'a mentionné, d'autres variables figurent dans la section Pieds et En-têtes de la documentation .

60
makro

Parmi quelques autres paramètres, le numéro de page et le nombre total de pages sont passés au pied de page HTML en tant que paramètre de requête, comme indiqué dans la documentation officielle:

... les arguments [numéro de page] sont envoyés aux documents HTML en-tête/pied de page à la manière de GET.

Source: http://wkhtmltopdf.org/usage/wkhtmltopdf.txt

La solution consiste donc à récupérer ces paramètres en utilisant un peu de JS et à les rendre dans le modèle HTML. Voici un exemple de travail complet d'un pied de page 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() est appelé dans body onload. Nous récupérons ensuite chaque variable prise en charge à partir de la chaîne de requête et remplaçons le contenu de tous les éléments par un nom de classe correspondant.

30
theDmi

De la documentation wkhtmltopdf ( http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtltltdfdf-0.9.9-doc.html ) sous la rubrique "Pieds de page et en-têtes", vous trouverez un extrait de code à réaliser page numérotage:

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

Il existe également un plus grand nombre de variables disponibles pouvant être substituées, autres que les numéros de page, à utiliser dans les en-têtes/pieds de page.

14
Richard Pursehouse

La façon dont cela DEVRAIT être fait (c’est-à-dire si wkhtmltopdf le supporte) utilise le support CSS paginé approprié: http://www.w3.org/TR/css3-gcpm/

Je cherche ce qu'il faudra faire maintenant.

1
rainabba

Approche sécurisée, même si vous utilisez XHTML (par exemple, avec thymeleaf). La seule différence avec la solution de tiers réside dans l'utilisation des balises //.

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

Dernière remarque: si vous utilisez thymeleaf, remplacez <script> par <script th:inline="javascript">.

1
Juangui Jordán