JavaScriptを使用してdiv内のHTMLからPDFを生成します


232

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

私がやりたいのは、「pdf」というIDを持つdivで見つかったものをすべてPDFに出力することです。これはJavaScriptを使用して行う必要があります。「pdf」ドキュメントは、「foobar.pdf」というファイル名で自動的にダウンロードされます。

私はこれを行うためにjspdfを使用してきましたが、それが持つ唯一の機能は、文字列値のみを受け入れる「テキスト」です。テキストではなくHTMLをjspdfに送信したい。


1
上記のように、「テキスト」機能を使用したくありません。私はそれにHTMLを与えたいです。リンクはプレーンテキストのみを扱い、HTMLは扱いません
John Crawford

2
jsPDFにfromHTML関数があります。「HTMLレンダラー」の例を参照してください:mrrio.github.io/jsPDF
mg1075

ここjsPDFチュートリアルを試してみてくださいfreakyjolly.com/create-multipage-html-pdf-jspdf-html2canvas
コードスパイ

回答:


228

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

特定の要素を無視する場合は、それらをIDでマークする必要があります。IDは、jsPDFの特別な要素ハンドラーで無視できます。したがって、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を作成しました。

特別な要素ハンドラーは、GitHub Issueにも記載されている現在のバージョンのIDのみを処理することに注意してください。それは述べています:

マッチングはノードツリーのすべての要素に対して行われるので、できるだけ速くしたいと思っていました。その場合、「要素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"など)現時点では、他のタイプのセレクタ(クラス、コンパウンド)はサポートされていません。

追加する1つの非常に重要なことは、スタイル情報(CSS)をすべて失うことです。幸い、jsPDFはh1、h2、h3などを適切にフォーマットでき、私の目的には十分でした。さらに、テキストノード内のテキストのみを印刷します。つまり、textareasなどの値は印刷しません。例:

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

3
要素ハンドラーはクラスにできると思いますか?これは、セマンティック上、HTML5標準に沿ったものになります。IDは、CSSで重要度が高すぎるだけでなく、一意である必要もあります。
2015年

いいえ、私が知る限り、現時点ではクラスは有効なセレクターではありません:「特別な要素ハンドラーをサポートしています。IDまたはノード名のjQueryスタイルIDセレクターで登録してください( "#iAmID"、 「div」、「span」など)現時点では、他のタイプのセレクター(クラス、コンパウンド)はサポートされていません。それでも、ユースケースに沿っていて、ページ上の他の重要な要素を非表示にしない場合は、タグ名を使用できます。
snrlx 2015年

彼らのページparall.ax/products/jspdfには、shim経由でIE6 +をサポートしていると記載されています。自分で試したことがありません。
snrlx 2015年

2
@snrlx空白のpdfとこのエラーが表示されます:renderer.pdf.sHashCodeは関数ではありません
Lisa Solomon

5
「特定の要素を無視したい場合は、IDでマークする必要があります」-その逆の要求によって台無しにされた素晴らしいライブラリ。OPは<div>、何百もの1つになる可能性がある単一のを印刷したかったので、不要な DOM要素をすべてマークする必要がありますか?
Mawgはモニカを2017

53

これは簡単な解決策です。これは私にとってはうまくいきます。JavaScriptの印刷コンセプトを使用して、これを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>

27
「簡単にこれをPDFとして保存」-その部分を逃しました。どうやってやるの?
Mawgはモニカを2017

9
これは私にとってはうまくいきました、CSSスタイルの問題を解決するために、printPDF.cssと呼ばれる別のcssファイルを作成し、上記の例のようにlinkタグを使用して追加しました:printWindow.document.write( '<html> <head> <title> DIVの内容</ title> '); printWindow.document.write( '<link rel = "stylesheet" href = "../ css / printPDF.css" />'); printWindow.document.write( '</ head> <body>');
Prime_Coder 2017

2
いくつかのコメント:1)印刷に特定のスタイルシートは必要ありません。現在のスタイルシートで、次のようにします。@media print {.pageBreak {page-break-before:always; } .labelPdf {font-weight:bold; font-size:20px; } .noPrintPdf {display:none; 必要に応じてこれらのクラスを使用してください。2).live( "click"、...)が機能しないため、代わりに.on( "click"、...)を使用します。
デビッドソンリマ

1
@DavidsonLimaこのコードは、古いウィンドウのCSSを表示しない新しいウィンドウを作成します。それがCSSを「無視」している理由です、それは無視していません。新しいウィンドウではロードされません。ヘッドにロードするだけでレンダリングされます。
Lukas Liesis、2018年

1
Angularでこれを実現しようとしている人がいる場合に備えて、CSSファイルをassetsフォルダーに入れてください。
rgantla

16

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
}

1
私は好奇心旺盛ですが、これはOP以外の誰かのために働いたことがありますか?コードを読んだところ、IDを持つ要素でのみ機能することがわかりました。それはおそらくそれよりも少し複雑です。とにかく、私はこれをどのように機能させるかを知りません。
マイケル

14
私が観察したところから、非常に皮肉なことに、fromHTMLは、パラメーターとして送信された要素にHTMLが含まれていない場合にのみ機能します。プレーンテキストのみがサポートされています。ちょっとはイモ全体の目的を殺します。
マイケル、

私には完璧に働きました。渡す要素は、必ずしもIDを持つ必要はありません。これが、レプリカントが渡したいノードを見つけた方法です。さらに、このソリューションは、「printDoc.autoPrint()」がなくても機能します。この特定の行をコードに残したい場合は、autoPrint-Pluginを含める必要があります。
snrlx 14

13

特定のページのPDFをダウンロードする必要がある場合は、このようなボタンを追加してください

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

window.print()を使用して、divだけでなくすべてのページを印刷します


2
それに加えて、単純な、あなたはIFRAMEのダウンロード可能なPDFファイルを作成したい場合は、デベロッパーコンソールを使用します document.querySelector("#myIframe").contentWindow.print()
ioCron

11

前述のように、jsPDFhtml2canvasを使用する必要があります。jsPDFの問題の中に、pdfを自動的に複数のページ(ソース)に分割する関数も見つかりました

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

3
画像は変換されません
Probosckie

1
答えてくれてありがとう。A4ページ形式にする方法についてヒントを教えてください。
johannesMatevosyan

3
これは実際には優れたベクターPDFを作成するのではなく、キャンバスで多くのビットマップを作成し、それらを画像としてスタックします。結果には多くの欠点があります-大きく、低品質で、PDFからコピーして貼り付けることができないなど
Roman Zenka

6

1つの方法はwindow.print()関数を使用することです。ライブラリを必要としないもの

長所

1.外部ライブラリは必要ありません。

2.体の一部だけをプリントすることもできます。

3. cssの競合やjsの問題はありません。

4.コアhtml / js機能

---単にコードの下に追加

CSS to

@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クリックでbewlow関数を呼び出す

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

注:すべてのcssオブジェクトで!importantを使用してください

例-

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

ブラウザの印刷機能に問題があります。ユーザーは通常、印刷ビューに対してデフォルトのオプション(マージン、ページサイズなど)を選択しています。したがって、ユーザーをトレーニングせずに必要なスタイリングで必要なPDFを生成することは非常に困難です。これは、はるかに困難でほぼ不可能です...
Rahmat Ali

4

CSSレンダリングにjspdfhtml2canvasを使用し、これが私のコードであるため、特定のdivのコンテンツをエクスポートします

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

        });
});

これは機能しますが、コンテンツを画像に変換します
Samad

また、現在のページに収まらない場合にコンテンツ/画像が新しいページに印刷されるように改ページを設定するにはどうすればよいですか?
SHEKHAR SHETE

4
  • 依存関係なし、純粋なJS
  • CSSまたは画像を追加するには、相対URLを使用せず、完全なURL http://...domain.../path.cssなどを使用します。別のHTMLドキュメントを作成し、主な内容のコンテキストはありません。
  • 画像をbase64として埋め込むこともできます

これは私に何年も役立った:

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

1
この問題は、PDFにCSS効果がないことです。
Shadab Faiz、2018

@ShadabFaizできますが、メインウィンドウとは異なる場合があります。このHTMLでもカスタムCSSを追加できます。
Lukas Liesis、2018年

うん。ウィンドウにcssを追加できますが、結果をファイルpdfに印刷するにはどうすればよいですか?
Mirko Cianfarani、

1
ただし、画像はレンダリングされません。
Jan Pi

1
これ大好き!あちこちに微調整を加えて、見栄えがいいです。そして、1つの小さなことで<body >、必要な余分なスペースが削除されない:P
Phil Roggenbuck

2

テーブルをエクスポートする場合は、シールドUIグリッドウィジェットが提供するこのエクスポートサンプルをご覧ください。

これは、次のように構成を拡張することによって行われます。

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

「PDFにエクスポート」機能により、空のPDFドキュメントが生成されました。
Richard Nalezynski、2016年

おそらくあなたの側で間違った設定...必要に応じて、shielduiタグで質問を投稿してください
Vladimir Georgiev

2

使用pdfMake.js、この要旨

(私はここで Gistをパッケージhtml-to-pdfmakeへのリンクと一緒に見つけましたが、今のところ使用していません。)

npm install pdfmakeとで要旨を保存htmlToPdf.js私はこのようにそれを使用します。

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

備考:

  • 私の使用例は、マークダウンドキュメント(markdown-itを使用)から関連するhtmlを作成し、続いてPDFを生成し、そのバイナリコンテンツ(pdfMakegetBuffer()関数で取得できます)をすべてブラウザからアップロードすることです。生成されたpdfは、この種のhtmlに対して、私が試した他のソリューションよりも優れていることがわかりました。
  • jsPDF.fromHTML()解決策は、HTML内の特殊文字によってマークアップの一種と解釈され、結果のPDFを完全に混乱させるため、ソリューションが混乱しやすいため、私は受け入れられた回答で提案した結果に不満があります。
  • jsPDF.from_html()キャンバスベースのソリューションはビットマップベースのPDFを生成しますが、生成されたPDFのテキストを貼り付け可能にしたいので、キャンバスベースのソリューション(非推奨の関数のように、受け入れられた回答の機能と混同しないでください)を使用することはできません。
  • md-to-pdfのようなPDFコンバーターへの直接のマークダウンはサーバー側のみであり、私には機能しません。
  • 生成されたPDFを表示したくないが、バイナリコンテンツをアップロードしたくないので、ブラウザの印刷機能を使用しても機能しません。

コードを正しく読んだ場合、これはCSSの境界線スタイル(テーブルなど)をサポートしていません。
ninjagecko

1

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>

2
htmlを渡す方法の例を投稿できます
Erum

しかし、コードは<script src = " html2canvas.hertzen.com/build/html2canvas.js "> < / >です。つまり、インターネットが必要ですか。
Erum

1
@Erumあなたはファイルをダウンロードすることができます。
Eduardo Cuomo 2016年

0

divをPDFとしてキャプチャするには、https://grabz.itソリューションを使用できます。簡単で柔軟なJavaScript APIを備えており、divやspanなどの単一のHTML要素のコンテンツをキャプチャできます。

これを実装するには、まずアプリのキーとシークレットを取得し、(無料の)SDK をダウンロードする必要があります。

そして今の例。

あなたが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>

features idの下にあるものをキャプチャするには、次のことを行う必要があります。

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

ご注意くださいtarget: #feature#feature前の例のようなCSSセレクターです。これで、ページが読み込まれると、スクリーンショットがスクリプトタグと同じ場所に作成されます。これには、機能divのコンテンツがすべて含まれ、他には何も含まれません。

div-screenshotメカニズムに対して実行できるその他の構成とカスタマイズがあります。こちらで確認してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.