web-dev-qa-db-fra.com

Générer des pdf à partir de HTML en div en utilisant Javascript

J'ai le code HTML suivant:

<!DOCTYPE html>
<html>
    <body>
        <p>don't print this to pdf</p>
        <div id="pdf">
            <p><font size="3" color="red">print this to pdf</font></p>
        </div>
    </body>
</html>

Tout ce que je veux, c'est imprimer en pdf tout ce qui se trouve dans la division avec un identifiant de "pdf". Cela doit être fait en utilisant JavaScript. Le document "pdf" devrait alors être automatiquement téléchargé avec un nom de fichier "foobar.pdf"

J'utilise jspdf pour cela, mais sa seule fonction est "text", qui accepte uniquement les valeurs de chaîne. Je veux soumettre HTML au format jspdf, pas du texte. 

171
John Crawford

jsPDF est capable d'utiliser des plugins. Afin de lui permettre d'imprimer du HTML, vous devez inclure certains plugins et donc procéder comme suit:

  1. Allez sur https://github.com/MrRio/jsPDF et téléchargez la dernière version.
  2. Incluez les scripts suivants dans votre projet:
    • jspdf.js
    • jspdf.plugin.from_html.js
    • jspdf.plugin.split_text_to_size.js
    • jspdf.plugin.standard_fonts_metrics.js

Si vous souhaitez ignorer certains éléments, vous devez les marquer avec un ID que vous pouvez ensuite ignorer dans un gestionnaire d'éléments spécial de jsPDF. Par conséquent, votre code HTML devrait ressembler à ceci:

<!DOCTYPE html>
<html>
  <body>
    <p id="ignorePDF">don't print this to pdf</p>
    <div>
      <p><font size="3" color="red">print this to pdf</font></p>
    </div>
  </body>
</html>

Ensuite, vous utilisez le code JavaScript suivant pour ouvrir le PDF créé dans un PopUp:

var doc = new jsPDF();          
var elementHandler = {
  '#ignorePDF': function (element, renderer) {
    return true;
  }
};
var source = window.document.getElementsByTagName("body")[0];
doc.fromHTML(
    source,
    15,
    15,
    {
      'width': 180,'elementHandlers': elementHandler
    });

doc.output("dataurlnewwindow");

Pour moi, cela a créé un Nice et ordonné PDF qui ne comprenait que la ligne 'print this to pdf'.

Veuillez noter que les gestionnaires d’éléments spéciaux ne traitent que les identifiants de la version actuelle, ce qui est également indiqué dans GitHub Issue . Il est dit: 

Comme la correspondance est faite avec chaque élément de l’arborescence de nœuds, mon désir était de la rendre aussi rapide que possible. Dans ce cas, cela signifiait "Seuls les ID d'élément sont appariés". Les ID d'élément sont toujours définis dans le style jQuery "#id", mais cela ne signifie pas que tous les sélecteurs jQuery sont pris en charge.

Par conséquent, remplacer "#ignorePDF" par des sélecteurs de classe tels que ".ignorePDF" ne fonctionnait pas pour moi. Au lieu de cela, vous devrez ajouter le même gestionnaire pour chaque élément que vous souhaitez ignorer, comme ceci:

var elementHandler = {
  '#ignoreElement': function (element, renderer) {
    return true;
  },
  '#anotherIdToBeIgnored': function (element, renderer) {
    return true;
  }
};

Les exemples indiquent également qu'il est possible de sélectionner des balises telles que 'a' ou 'li'. Cela pourrait être un peu trop restrictif pour la plupart des cas:

Nous soutenons les gestionnaires d'éléments spéciaux. Enregistrez-les avec jQuery-style Sélecteur d'identifiant pour l'identifiant ou le nom du noeud. ("#iAmID", "div", "span" etc.) Aucun autre type de sélecteur (classe, composé .__) n'est pris en charge pour le moment.

Une chose très importante à ajouter est que vous perdez toutes vos informations de style (CSS). Heureusement, jsPDF est capable de bien formater h1, h2, h3, etc., ce qui était suffisant pour mes besoins. De plus, il n’imprimera que le texte dans les nœuds de texte, ce qui signifie qu’il n’imprimera pas les valeurs textareas et autres. Exemple:

<body>
  <ul>
    <!-- This is printed as the element contains a textnode -->        
    <li>Print me!</li>
  </ul>
  <div>
    <!-- This is not printed because jsPDF doesn't deal with the value attribute -->
    <input type="textarea" value="Please print me, too!">
  </div>
</body>
169
snrlx

C'est la solution simple. Cela fonctionne pour moi. Vous pouvez utiliser le concept d'impression javascript et le sauvegarder au format PDF.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script type="text/javascript">
        $("#btnPrint").live("click", function () {
            var divContents = $("#dvContainer").html();
            var printWindow = window.open('', '', 'height=400,width=800');
            printWindow.document.write('<html><head><title>DIV Contents</title>');
            printWindow.document.write('</head><body >');
            printWindow.document.write(divContents);
            printWindow.document.write('</body></html>');
            printWindow.document.close();
            printWindow.print();
        });
    </script>
</head>
<body>
    <form id="form1">
    <div id="dvContainer">
        This content needs to be printed.
    </div>
    <input type="button" value="Print Div Contents" id="btnPrint" />
    </form>
</body>
</html>
32
vaibhav kulkarni

Vous pouvez utiliser autoPrint () et définir la sortie sur 'dataurlnewwindow' comme ceci:

function printPDF() {
    var printDoc = new jsPDF();
    printDoc.fromHTML($('#pdf').get(0), 10, 10, {'width': 180});
    printDoc.autoPrint();
    printDoc.output("dataurlnewwindow"); // this opens a new popup,  after this the PDF opens the print window view but there are browser inconsistencies with how this is handled
}
14
Marco

Comme mentionné, vous devez utiliser jsPDF et html2canvas . J'ai également trouvé une fonction dans les numéros de jsPDF qui divise automatiquement votre pdf en plusieurs pages ( sources )

function makePDF() {

    var quotes = document.getElementById('container-fluid');

    html2canvas(quotes, {
        onrendered: function(canvas) {

        //! MAKE YOUR PDF
        var pdf = new jsPDF('p', 'pt', 'letter');

        for (var i = 0; i <= quotes.clientHeight/980; i++) {
            //! This is all just html2canvas stuff
            var srcImg  = canvas;
            var sX      = 0;
            var sY      = 980*i; // start 980 pixels down for every new page
            var sWidth  = 900;
            var sHeight = 980;
            var dX      = 0;
            var dY      = 0;
            var dWidth  = 900;
            var dHeight = 980;

            window.onePageCanvas = document.createElement("canvas");
            onePageCanvas.setAttribute('width', 900);
            onePageCanvas.setAttribute('height', 980);
            var ctx = onePageCanvas.getContext('2d');
            // details on this usage of this function: 
            // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
            ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);

            // document.body.appendChild(canvas);
            var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);

            var width         = onePageCanvas.width;
            var height        = onePageCanvas.clientHeight;

            //! If we're on anything other than the first page,
            // add another page
            if (i > 0) {
                pdf.addPage(612, 791); //8.5" x 11" in pts (in*72)
            }
            //! now we declare that we're working on that page
            pdf.setPage(i+1);
            //! now we add content to that page!
            pdf.addImage(canvasDataURL, 'PNG', 20, 40, (width*.62), (height*.62));

        }
        //! after the for loop is finished running, we save the pdf.
        pdf.save('test.pdf');
    }
  });
}
8
BaptWaels

si vous avez besoin de télécharger le pdf d'une page spécifique, ajoutez un bouton comme celui-ci

<h4 onclick="window.print();"> Print </h4>

utilisez window.print () pour imprimer toute votre page, pas seulement une div

2
Wael Mahmoud

Si vous souhaitez exporter une table, vous pouvez consulter cet exemple d'exportation fourni par le widget Grille d'interface utilisateur de bouclier.

Cela se fait en étendant la configuration comme ceci:

...
exportOptions: {
    proxy: "/filesaver/save",
    pdf: {
        fileName: "shieldui-export",
        author: "John Smith",
        dataSource: {
            data: gridData
        },
        readDataSource: true,
        header: {
            cells: [
                { field: "id", title: "ID", width: 50 },
                { field: "name", title: "Person Name", width: 100 },
                { field: "company", title: "Company Name", width: 100 },
                { field: "email", title: "Email Address" }
            ]
        }
    }
}
...
2
Vladimir Georgiev

Pour capturer div en tant que PDF, vous pouvez utiliser la solution https://grabz.it . Il dispose d'une API JavaScript simple et flexible qui vous permettra de capturer le contenu d'un seul élément HTML, tel qu'un div ou un span.

Pour l'implémenter, vous devez d'abord obtenir une clé app et un secret et télécharger le SDK (gratuit). 

Et maintenant un exemple.

Disons que vous avez le code HTML:

<div id="features">
    <h4>Acme Camera</h4>
    <label>Price</label>$399<br />
    <label>Rating</label>4.5 out of 5
</div>
<p>Cras ut velit sed purus porttitor aliquam. Nulla tristique magna ac libero tempor, ac vestibulum felisvulput ate. Nam ut velit eget
risus porttitor tristique at ac diam. Sed nisi risus, rutrum a metus suscipit, euismod tristique nulla. Etiam venenatis rutrum risus at
blandit. In hac habitasse platea dictumst. Suspendisse potenti. Phasellus eget vehicula felis.</p>

Pour capturer ce qui se trouve sous les caractéristiques, vous devez:

//add the sdk
<script type="text/javascript" src="grabzit.min.js"></script>
<script type="text/javascript">
//login with your key and secret. 
GrabzIt("KEY", "SECRET").ConvertURL("http://www.example.com/my-page.html",
{"target": "#features", "format": "pdf"}).Create();
</script>

Veuillez noter le target: #feature. #feature est votre sélecteur CSS, comme dans l'exemple précédent. Maintenant, lorsque la page est chargée, une image d’écran sera créée au même emplacement que la balise script, qui contiendra tout le contenu de la fonction div et rien d’autre.

Il existe d’autres configurations et personnalisations que vous pouvez utiliser pour le mécanisme div-screenshot, consultez-les ici

0
Stas
  • Pas de dépendances, pur JS

Cela m'a servi pendant des années maintenant:

export default function printDiv({divId, title}) {
  let mywindow = window.open('', 'PRINT', 'height=650,width=900,top=100,left=150');

  mywindow.document.write(`<html><head><title>${title}</title>`);
  mywindow.document.write('</head><body >');
  mywindow.document.write(document.getElementById(divId).innerHTML);
  mywindow.document.write('</body></html>');

  mywindow.document.close(); // necessary for IE >= 10
  mywindow.focus(); // necessary for IE >= 10*/

  mywindow.print();
  mywindow.close();

  return true;
}
0
Lukas

Utilisez pdfMake.js et this Gist .

(J'ai trouvé le Gist ici avec un lien vers le package html-to-pdfmake , que je finis par ne pas utiliser pour l'instant.)

Après npm install pdfmake et avoir sauvegardé le Gist dans htmlToPdf.js, je l’utilise comme ceci:

const pdfMakeX = require('pdfmake/build/pdfmake.js');
const pdfFontsX = require('pdfmake-unicode/dist/pdfmake-unicode.js');
pdfMakeX.vfs = pdfFontsX.pdfMake.vfs;
import * as pdfMake from 'pdfmake/build/pdfmake';
import htmlToPdf from './htmlToPdf.js';

var docDef = htmlToPdf(`<b>Sample</b>`);
pdfMake.createPdf({content:docDef}).download('sample.pdf');

Remarques:

  • Mon cas d’utilisation consiste à créer le code HTML approprié à partir d’un document de démarquage (avec markdown-it ), puis à générer le fichier PDF et à en télécharger le contenu binaire (que je peux obtenir avec la fonction getBuffer() de pdfMake ), tous à partir du navigateur. Le fichier PDF généré s’avère plus intéressant pour ce type de HTML qu'avec d’autres solutions que j’ai essayées.
  • Je ne suis pas satisfait des résultats de jsPDF.fromHTML() suggérés dans la réponse acceptée, car cette solution est facilement perturbée par les caractères spéciaux de mon code HTML qui sont apparemment interprétés comme une sorte de balisage et qui gâchent totalement le fichier PDF résultant.
  • Utiliser des solutions de type canvas (comme la fonction obsolète jsPDF.from_html(), à ne pas confondre avec celle de la réponse acceptée) n’est pas une option pour moi, car je souhaite que le texte du PDF généré soit collable, alors que canvas les solutions basées génèrent des PDF basés sur bitmap.
  • Le démarquage direct vers les convertisseurs pdf comme md-to-pdf ne concerne que le serveur et ne fonctionnerait pas pour moi.
  • L'utilisation de la fonctionnalité d'impression du navigateur ne fonctionnerait pas pour moi car je ne souhaite pas afficher le PDF généré mais _ télécharger son contenu binaire.
0
ilmiacs

j'utilise jspdf et html2canvase pour le rendu css et j'exporte le contenu de div spécifique car c'est mon code

$(document).ready(function () {
    let btn=$('#c-oreder-preview');
    btn.text('download');
    btn.on('click',()=> {

        $('#c-invoice').modal('show');
        setTimeout(function () {
            html2canvas(document.querySelector("#c-print")).then(canvas => {
                //$("#previewBeforeDownload").html(canvas);
                var imgData = canvas.toDataURL("image/jpeg",1);
                var pdf = new jsPDF("p", "mm", "a4");
                var pageWidth = pdf.internal.pageSize.getWidth();
                var pageHeight = pdf.internal.pageSize.getHeight();
                var imageWidth = canvas.width;
                var imageHeight = canvas.height;

                var ratio = imageWidth/imageHeight >= pageWidth/pageHeight ? pageWidth/imageWidth : pageHeight/imageHeight;
                //pdf = new jsPDF(this.state.orientation, undefined, format);
                pdf.addImage(imgData, 'JPEG', 0, 0, imageWidth * ratio, imageHeight * ratio);
                pdf.save("invoice.pdf");
                //$("#previewBeforeDownload").hide();
                $('#c-invoice').modal('hide');
            });
        },500);

        });

});

0
ghazaleh javaheri

J'ai réussi à obtenir que jsPDF imprime des tables créées dynamiquement à partir d'un div.

$(document).ready(function() {

        $("#pdfDiv").click(function() {

    var pdf = new jsPDF('p','pt','letter');
    var specialElementHandlers = {
    '#rentalListCan': function (element, renderer) {
        return true;
        }
    };

    pdf.addHTML($('#rentalListCan').first(), function() {
        pdf.save("caravan.pdf");
    });
    });
});

Fonctionne très bien avec Chrome et Firefox ... Le formatage est tout éclaté dans IE.

J'ai aussi inclus ceux-ci:

<script src="js/jspdf.js"></script>
    <script src="js/jspdf.plugin.from_html.js"></script>
    <script src="js/jspdf.plugin.addhtml.js"></script>
    <script src="//mrrio.github.io/jsPDF/dist/jspdf.debug.js"></script>
    <script src="http://html2canvas.hertzen.com/build/html2canvas.js"></script>
    <script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script>
    <script type="text/javascript" src="./libs/Blob.js/Blob.js"></script>
    <script type="text/javascript" src="./libs/deflate.js"></script>
    <script type="text/javascript" src="./libs/adler32cs.js/adler32cs.js"></script>

    <script type="text/javascript" src="js/jspdf.plugin.addimage.js"></script>
    <script type="text/javascript" src="js/jspdf.plugin.sillysvgrenderer.js"></script>
    <script type="text/javascript" src="js/jspdf.plugin.split_text_to_size.js"></script>
    <script type="text/javascript" src="js/jspdf.plugin.standard_fonts_metrics.js"></script>
0
Wasskinny

Une solution consiste à utiliser la fonction window.print (). Qui ne nécessite aucune bibliothèque

Avantages

1. Aucune bibliothèque externe requise.

2.Nous ne pouvons imprimer que certaines parties du corps.

3. Pas de conflits CSS et de problèmes JS.

4.Core fonctionnalité html/js

--- Ajoutez simplement le code ci-dessous

CSSto

@media print {
        body * {
            visibility: hidden; // part to hide at the time of print
            -webkit-print-color-adjust: exact !important; // not necessary use         
               if colors not visible
        }

        #printBtn {
            visibility: hidden !important; // To hide 
        }

        #page-wrapper * {
            visibility: visible; // Print only required part
            text-align: left;
            -webkit-print-color-adjust: exact !important;
        }
    }

Code JS - Appelez la fonction bewlow sur un clic de souris.

$scope.printWindow = function () {
  window.print()
}

Note: Utilisez! Important dans chaque objet css

Exemple -

.legend  {
  background: #9DD2E2 !important;
}
0
Rohit Parte