IT story

Javascript를 사용하여 div의 HTML에서 pdf 생성

hot-time 2020. 5. 9. 09:17
반응형

Javascript를 사용하여 div의 HTML에서 pdf 생성


다음 HTML 코드가 있습니다.

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

내가하고 싶은 것은 ID가 "pdf"인 div에있는 모든 것을 pdf로 인쇄하는 것입니다. JavaScript를 사용하여 수행해야합니다. "pdf"문서는 "foobar.pdf"파일 이름으로 자동 다운로드되어야합니다.

이 작업을 수행하기 위해 jspdf를 사용해 왔지만, 유일한 기능은 문자열 값만 허용하는 "text"입니다. 텍스트가 아닌 HTML을 jspdf에 제출하고 싶습니다.


jsPDF는 플러그인을 사용할 수 있습니다. HTML을 인쇄 할 수있게하려면 특정 플러그인을 포함시켜야하므로 다음을 수행해야합니다.

  1. https://github.com/MrRio/jsPDF로 이동 하여 최신 버전을 다운로드하십시오.
  2. 프로젝트에 다음 스크립트를 포함하십시오.
    • jspdf.js
    • jspdf.plugin.from_html.js
    • jspdf.plugin.split_text_to_size.js
    • jspdf.plugin.standard_fonts_metrics.js

특정 요소를 무시하려면 jsPDF의 특수 요소 처리기에서이를 무시할 수있는 ID로 표시해야합니다. 따라서 HTML은 다음과 같아야합니다.

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

그런 다음 다음 JavaScript 코드를 사용하여 작성된 PDF를 팝업으로여십시오.

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");

나를 위해 이것은 'pdf로 인쇄'행만 포함하는 멋지고 깔끔한 PDF를 만들었습니다.

특수 요소 핸들러는 현재 버전의 ID 만 처리하며 GitHub Issue에 명시되어 있습니다 . 상태는 다음과 같습니다.

노드 트리의 모든 요소에 대해 일치가 이루어지기 때문에 가능한 한 빨리 만들려고했습니다. 이 경우 "요소 ID 만 일치"를 의미합니다. 요소 ID는 여전히 jQuery 스타일 "#id"로 수행되지만 모든 jQuery 선택기가 지원되는 것은 아닙니다.

따라서 '#ignorePDF'를 '.ignorePDF'와 같은 클래스 선택기로 바꾸면 나에게 도움이되지 않습니다. 대신 각 요소마다 동일한 핸들러를 추가해야합니다.

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

에서 'a'또는 'li'와 같은 태그를 선택할 수 있다고 언급되어 있습니다. 그래도 대부분의 유스 케이스에는 제한이 없을 수 있습니다.

특수 요소 처리기를 지원합니다. ID 또는 노드 이름에 대해 jQuery 스타일 ID 선택기로 등록하십시오. ( "#iAmID", "div", "span"등) 현재 다른 유형의 선택기 (클래스, 컴파운드)는 지원하지 않습니다.

추가해야 할 중요한 사항 중 하나는 모든 스타일 정보 (CSS)를 잃어버린다는 것입니다. 운 좋게도 jsPDF는 h1, h2, h3 등을 멋지게 포맷 할 수있어 내 목적에 충분했습니다. 또한 텍스트 노드 내에서만 텍스트를 인쇄하므로 텍스트 영역 등의 값을 인쇄하지 않습니다. 예:

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

이것은 간단한 해결책입니다. 자바 스크립트 인쇄 개념을 사용하고 이것을 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>

autoPrint ()를 사용하고 다음과 같이 출력을 'dataurlnewwindow'로 설정할 수 있습니다.

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
}

언급 한대로 jsPDFhtml2canvas 를 사용해야합니다 . 또한 pdf를 여러 페이지 ( 소스 ) 로 자동 분할하는 jsPDF 문제 내부의 기능을 발견했습니다.

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

특정 페이지의 PDF를 다운로드 해야하는 경우 다음과 같은 버튼을 추가하십시오.

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

div뿐만 아니라 모든 페이지를 인쇄하려면 window.print () 사용


한 가지 방법은 window.print () 함수를 사용하는 것입니다. 어떤 라이브러리가 필요하지 않습니다

찬성

1. 외부 라이브러리가 필요하지 않습니다.

2. 우리는 또한 본문의 선택한 부분 만 인쇄 할 수 있습니다.

3. CSS 충돌 및 JS 문제가 없습니다.

4. 핵심 html / js 기능

--- 간단히 아래 코드를 추가

CSS

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

JS 코드 -BTN 클릭시 다음 함수 호출

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

참고 : 모든 CSS 객체에서! important를 사용하십시오.

예 -

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

테이블을 내보내려면 Shield UI Grid 위젯에서 제공 한이 내보내기 샘플을 살펴볼 수 있습니다 .

다음과 같이 구성을 확장하여 수행됩니다.

...
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" }
            ]
        }
    }
}
...

CSS 렌더링에 jspdfhtml2canvas사용 하고 특정 코드의 내용을 내 코드로 내 보냅니다.

$(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);

        });
});

jsPDF가 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");
    });
    });
});

Chrome 및 Firefox에서 잘 작동합니다. IE에서 서식이 모두 향상되었습니다.

나는 또한 이것을 포함했다 :

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

  • 의존성 없음, 순수한 JS

이것은 지금 몇 년 동안 나에게 도움이되었습니다.

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

div를 PDF로 캡처하려면 https://grabz.it 솔루션을 사용할 수 있습니다 . 쉽고 유연하며 div 또는 span과 같은 단일 HTML 요소의 내용을 캡처 할 수있는 JavaScript API가 있습니다.

In order to implement it you will need to first get an app key and secret and download the (free) SDK.

And now an example.

Let's say you have the 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>

To capture what is under the features id you will need to:

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

Please note the target: #feature. #feature is you CSS selector, like in the previous example. Now, when the page is loaded an image screenshot will now be created in the same location as the script tag, which will contain all of the contents of the features div and nothing else.

The are other configuration and customization you can do to the div-screenshot mechanism, please check them out here


Use pdfMake.js and this Gist.

(I found the Gist here along with a link to the package html-to-pdfmake, which I end up not using for now.)

After npm install pdfmake and saving the Gist in htmlToPdf.js I use it like this:

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');

Remarks:

  • My use case is to create the relevant html from a markdown document (with markdown-it) and subsequently generating the pdf, and uploading its binary content (which I can get with pdfMake's getBuffer() function), all from the browser. The generated pdf turns out to be nicer for this kind of html than with other solutions I have tried.
  • I am dissatisfied with the results I got from jsPDF.fromHTML() suggested in the accepted answer, as that solution gets easily confused by special characters in my HTML that apparently are interpreted as a sort of markup and totally mess up the resulting PDF.
  • Using canvas based solutions (like the deprecated jsPDF.from_html() function, not to be confused with the one from the accepted answer) is not an option for me since I want the text in the generated PDF to be pasteable, whereas canvas based solutions generate bitmap based PDFs.
  • Direct markdown to pdf converters like md-to-pdf are server side only and would not work for me.
  • Using the printing functionality of the browser would not work for me as I do not want to display the generated PDF but upload its binary content.

jsPDF is updated. here is the correct code

var doc = new jsPDF();
doc.text(20, 20, 'Hello world!');
doc.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');
doc.addPage();
doc.text(20, 20, 'Do you like that?');
doc.save('Test.pdf');

참고URL : https://stackoverflow.com/questions/18191893/generate-pdf-from-html-in-div-using-javascript

반응형