HTMLからPDFへの変換のための純粋なクライアント側と純粋なサーバー側の実装ソリューション

HTMLからPDFへの変換のための純粋なクライアント側と純粋なサーバー側の実装ソリューション

必要

ユーザーがフォームに入力して「保存」をクリックすると、PDF ドキュメントを直接ダウンロードできます。

解決

サーバー世代

アイデア

Google Chromeは2017年にChrome Headless機能を独自開発し、同時にPuppeteerをリリースしました。インターフェースがないブラウザでありながら、サーバー機能を完備していると言えます。

したがって、サーバー上で Puppeteer ブラウザを起動し、ターゲット URL を開き、Chrome ブラウザの組み込み変換機能を使用して HTML を PDF に変換できます。

サーバーがコアコードを生成する

まず、puppeteer をインストールする必要があります。NPM のインストールは失敗する可能性があります。cnpm Taobao ミラーを使用してインストールするのが最適です。

依存関係をインストールするには、 cnpm i puppeteer -Sと入力します。

js ファイルを作成し、Puppeteer ブラウザで URL を開いて PDF を保存します。

// html2pdf.js

'puppeteer' という定数が必要です。
(非同期関数(){
    // サービスを開始します const browser = await puppeteer.launch();
    // タブを開く const page = await browser.newPage();
    // このアドレスに移動します await page.goto('https://koa.bootcss.com/#context');
    // HTML ページを PDF に変換し、パスに保存します
    page.pdf({path:"test.pdf",format:'A4'}) を待ちます
    // ブラウザを閉じる await browser.close();
})();

次に、コンソールにnode html2pdf.jsと入力してサービスを開始します。

もちろん、ビジネス ロジックに応じて module.export を使用してモジュール メソッドをエクスポートすることもできます。

欠点

動的フォームデータを保存できません

ページはサーバーから要求されるため、ユーザー入力が要求アドレスに保存されていない場合、傍受された PDF は入力されていないページの初期状態になります。

つまり、静的なページしか変換できませんが、私たちの要件では大量のユーザー入力が必要なので、合格です。

クライアントがコアコードを生成する

アイデア

  • html2canvasを使用して、変換する必要があるDOMノードを入力し、それをトラバースしてキャンバスに変換します。
  • キャンバスを base64 イメージに変換し、jsPDF を使用して PDF ファイルを作成し、そのイメージを PDF に挿入します。

欠点

ねじれ。

ページのスクリーンショットを撮って、それを PDF に挿入するのと似ているため、ページの解像度と構成が出力画像の品質に影響を与える可能性が高いことがわかります。

同時に、スクリーンショットであるため、ページリンクなどの機能が失われる可能性があります。

テキストの切り捨て

キャンバスが PDF ページのサイズより大きい場合、出力は正しくありません。このとき、キャンバスが A4 サイズを超えているかどうかを判断する必要があります。超えている場合は、キャンバスを分割して別のページに挿入します。

ここで再び問題が発生します。画像がセグメント化されているため、キャンバス内のアイテムの構造を分析できず、画像またはテキストが半分に切り取られる可能性が非常に高くなります。

コアコード

私たちのニーズには画像やリンクは含まれていないため、歪みの問題はほとんど影響しません。同時に、私たちのフォームは同じ長さの複数の繰り返し項目で構成されており、これらの項目は非常に短く、A4 用紙を超えることはありません (これは厳密ではありませんが、必要に応じて、DOM 要素の幅と高さを取得し、DOM 要素の高さに応じて切り抜くことができます)。

そこで、アイテムごとにキャンバスを直接分割し、各アイテムを A4 用紙 1 ページに保存する予定です。

始める前に理解しておく必要があるコアメソッドがいくつかあります。

html2キャンバス

   // DOMは変換されるDOMノードです html2canvas(DOM,{
        背景色:"#ffffff",
        幅:幅、
        高さ:高さ、
        スケール:2,
        汚染を許可する:true、
    }).then((キャンバス)=>{
        // キャンバスは変換が成功した後のキャンバスです})

jsPDF

   // インスタンスを作成します。let pdf = new jsPDF('','pt','a4');
    // 画像を PDF ファイルに追加します // 最初のパラメーターは挿入するファイル形式 (base64)、2 番目はファイル形式です // 3 番目と 4 番目は画像の左上隅の座標、最後の 2 つは挿入後の画像の幅と高さです pdf.addImage(image,'JPEG',10,10,height,width);
    // 新しいページを追加する pdf.addPage()
    // PDFファイルを保存する pdf.save()

キャンバス

  // canvas は切り取る画像です // sx、sy は切り取りを開始する座標です // swidth、sHeight は切り取りの幅と高さです // dx、dy は切り取った画像を canvas に挿入する座標です // sWidth、sHeight は切り取った画像の canvas 内での幅と高さです cxt.drawImage(canvas, sx, sy, sWidth, sHeight, dx, dy, sWidth, sHeight);
/**
 * @description: フォームを PDF ファイルに変換します* @return: pdf
 */
送信(){
    // これは変換したいフォームです。このフォームには同一のフォームが多数あります。let form = this.$refs.form;
    // 要素の幅と高さを取得します。let width = form.getBoundingClientRect().width;
    高さを form.getBoundingClientRect().height に設定します。
    html2canvas(フォーム,{
        背景色:"#ffffff",
        幅:幅、
        高さ:高さ、
        スケール:2,
        汚染を許可する:true、
    }).then((キャンバス)=>{
        pdf = new jsPDF('','pt','a4');
        // 画像を切り取ります let canvasList = this.splitCanvas(canvas,this.forms.length);

        // キャンバスリストを走査し、各ページに画像を追加します canvasList.forEach((item,index)=>{
            // 画像フォーマットをbase64に変換する
            itemImage を item.toDataURL('image/jpeg',1.0); とします。
            // 10px の余白を確保します。A4 用紙の幅は 72 解像度のモニターでは 595px です。
            pdf.addImage(itemImage,'JPEG',10,10,575.28,575.28/item.width*item.height);
            // 最後のページでない場合は、ページ区切り index == this.forms.length-1 ? '' : pdf.addPage();
        })
        // ファイルを保存します。let blob = pdf.output('blob');
        
        pdf.save('test.pdf');
    })
},
/**
 * @description: キャンバスをカット * @param {number} num スライスの数 * @param {canvas} キャンバス 
 * @return {array} キャンバスリスト*/
splitCanvas(キャンバス,数値){
    高さを canvas.height、幅を canvas.width とします。
    let chunkHeight = height/num; // 各スライスの高さ let chunkList = []; // 結果のキャンバスを保存
    for(let i=0; i<height; i+=chunkHeight){
        // 切り抜き四角形の位置を初期化します。let sx = 0,sy = i,sWidth = width,sHeight = chunkHeight,dx = 0, dy = 0;
        // キャンバス ノードを作成します。let canvasItem = document.createElement("canvas");
        // キャンバス サイズを初期化します。canvasItem.height = chunkHeight;
        キャンバスアイテムの幅 = 幅;
        cxt = canvasItem.getContext("2d"); とします。
        // 切り取った画像を新しいキャンバス ノードに配置します。cxt.drawImage(canvas,sx,sy,sWidth,sHeight,dx,dy,sWidth,sHeight);
        chunkList.push(キャンバスアイテム); 
    }
    chunkList を返します。
},

最終結果

フォームを保存した後のページ

PDFへの変換の効果

これで、HTML から PDF への純粋なクライアント側および純粋なサーバー側の実装ソリューションに関するこの記事は終了です。HTML から PDF への関連コンテンツの詳細については、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  MySQL に外部キー制約を追加する具体的な方法

>>:  Dockerリンクはコンテナの相互接続を実現します

推薦する

MYSQL の 10 の典型的な最適化ケースとシナリオ

目次1. SQL最適化の一般的な手順1. SQL実行計画の分析を説明する2. プロフィール分析を表示...

Postman 自動インターフェーステストの実践

目次背景説明GETリクエストの作成事前リクエストスクリプトで署名を作成するスクリプトは環境変数に書き...

MySQL トランザクション分離レベルと MVCC の詳細な説明

目次トランザクション分離レベル同時トランザクション実行中に発生した問題SQL標準の4つの分離レベルM...

MySqlはページクエリ機能を実装します

まず、ページ分割クエリを使用する理由を明確にする必要があります。データが膨大なため、すべてのデータを...

Linux仮想マシンをWiFiに接続する方法

生活の中で、インターネットはどこにでもあります。インターネットを通じてゲームをしたり、テレビ番組を見...

表のセル間隔とセルパディングの違いの詳細な説明

テーブルとは何ですか?セルセルで構成されています。表では、<td> の数は、<tr...

スキニングを実現するネイティブJavaScript

ネイティブJavaScriptでスキニングを実装するための具体的なコードは参考までに。具体的な内容は...

Centos7環境でMySQL 5.6のインスタンスを複数作成する方法の詳細な説明

この記事では、CentOS 7 環境で MySQL 5.6 の複数のインスタンスを作成する方法につい...

ReactプロジェクトにSCSSを導入する方法

まず依存関係をダウンロードします yarn sass-loader ノード sass を追加します次...

vite2.x は ant-design-vue@next コンポーネントのオンデマンド読み込みを実装します。

1. 使用バージョンバイト:2.0 ant-design-vue: 2.0.0-rc.8ヴュー:3...

Div CSS 命名標準 CSS クラスの命名規則 (SEO 標準に準拠)

検索エンジン最適化 (SEO) では実行すべきタスクが多数ありますが、その中でもコードの最適化は重要...

antd+reactプロジェクトをviteに移行するためのソリューションの詳細な説明

Antd+react+webpackは、多くの場合、Reactテクノロジースタックに基づくフロントエ...

vue.js を使用してドラッグ アンド ドロップ機能を実装する方法

序文ドラッグ アンド ドロップ機能を追加すると、プログラムがより自然でユーザーフレンドリーになります...

jQuery における Ajax の関連知識ポイントのまとめ

序文JavaScriptを学ぶ学生は、 AJAX (非同期JavaScriptとxml) 変換は非同...

EXPLAIN コマンドの詳細な説明と MySQL での使用方法

1. シナリオの説明: 同僚から MySQL で explain を使用する方法を教わったので、返さ...