1. ホーム
  2. Web制作
  3. HTML/Xhtml

HTML to PDFのピュアクライアントサイドおよびピュアサーバーサイドの実装プログラム

2022-01-07 13:02:32

必要条件

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

ソリューションのアイデア

サーバーサイドの生成

アイデア

Google Chromeは17年にChrome Headless機能を独自に開発し、それと並行してpuppeteerを発売したが、これはインターフェースレスだがサーバー機能的な機能ができるブラウザと考えることができる。

そこで、サーバー側でpuppeteerブラウザーを起動し、対象のURLを開き、クローム独自の変換機能を使ってhtmlをpdfに変換することができる。

サーバーサイドでのコアコードの生成

最初にpuppeteerをインストールします。npmのインストールがエラーになる場合があります。

タイプ cnpm i puppeteer -S 依存関係をインストールします。

jsファイルを作成します。puppeteerブラウザでURLを開き、pdfを保存するだけです。

// html2pdf.js

const puppeteer = require('puppeteer');
(async function(){
    // Start the service
    const browser = await puppeteer.launch();
    // open the tabs
    const page = await browser.newPage();
    // Go to this address
    await page.goto('https://koa.bootcss.com/#context');
    // html page to pdf and save to path
    await page.pdf({path:"test.pdf",format:'A4'})
    // close the browser
    await browser.close();
})();

そして、コンソールは次のように入力します。 node html2pdf.js を実行して、サービスを開始します。

もちろん、ビジネスロジックによっては、module.export でモジュールのメソッドをエクスポートすることも可能です。

デメリット

フォームダイナミックデータを保存できない

ページはサーバーからリクエストされるので、ユーザー入力がリクエストアドレスに保存されていない場合、切り捨てられたpdfがページが埋まっていない初期状態となる。

つまり、彼は静的なページ変換しかできない、我々の要件はユーザー入力が多いのでパス。

クライアントサイドでのコアコードの生成

考えること

  • html2canvasを使用し、変換するdomノードを入力し、それを繰り返しながらcanvasに変換します。
  • canvasをbase64画像に変換し、jsPDFでpdfファイルを作成し、pdfに画像を挿入します。

不備な点

歪みがある。

ページのスクリーンショットを撮ってpdfに挿入するのと同じなので、ページの解像度や構成が出力画像の品質に影響しそうなことがよくわかりますね。

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

テキストの切り捨て

キャンバスがpdfの1ページより大きい場合、出力がおかしくなるので、キャンバスがA4サイズより大きいかどうか判断し、大きい場合は分割して別のページに挿入する必要があります。

ここでまた問題が発生します。分割しているため、キャンバス内のアイテムの構造を解析できず、画像やテキストが途中から切り捨てられる可能性が高いのです。

コアとなるコード

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

そこで、キャンバスをアイテムに基づいてスライスし、各アイテムにA4用紙1ページを与えて保管するだけにすることにします。

始める前に理解しておきたい、いくつかのコア・メソッド。

html2canvas

   // DOM is the DOM node to transform
    html2canvas(DOM,{
        backgroundColor:"#ffffff",
        width:width,
        height:height,
        scale:2,
        allowTaint:true,
    }).then((canvas)=>{
        // canvas is the canvas after a successful conversion
    })

jsPDF

   // Create an instance
    let pdf = new jsPDF('','pt','a4');
    // add the image to the pdf file
    // the first parameter is the file to be inserted (base64) format, the second is the file format
    // the third fourth is the coordinates of the upper left corner of the picture, the last two are the width and height of the picture after insertion
    pdf.addImage(image,'JPEG',10,10,height,width);
    // add a new page
    pdf.addPage()
    // save pdf file
    pdf.save()

キャンバス

  // canvas is the image to be cropped
    // sx, sy are the coordinates to start cropping
    // swidth, sHeight is the width and height of the crop
    // dx, dy are the coordinates where the cropped image is inserted in the canvas
    // sWidth,sHeight is the width and height of the cropped image in the canvas
    cxt.drawImage(canvas,sx,sy,sWidth,sHeight,dx,dy,sWidth,sHeight);

/**
 * @description: form to pdf file
 * @return: pdf
 */
onSubmit(){
    // This is the form I want to convert, which has many of the same forms
    let form = this.$refs.form;
    // Get the width and height of the element
    let width = form.getBoundingClientRect().width;
    let height = form.getBoundingClientRect().height;
    html2canvas(form,{
        backgroundColor:"#ffffff",
        width:width,
        height:height,
        scale:2,
        allowTaint:true,
    }).then((canvas)=>{
        let pdf = new jsPDF('','pt','a4');
        // for image cutting
        let canvasList = this.splitCanvas(canvas, this.forms.length);

        // iterate through the canvas list, adding one image per page
        canvasList.forEach((item,index)=>{
            // convert the image format to base64
            let itemImage = item.toDataURL('image/jpeg',1.0);
            // leave 10px margins, A4 paper width in 72 resolution monitor is 595px
            pdf.addImage(itemImage,'JPEG',10,10,575.28,575.28/item.width*item.height);
            // If not the last page, then paginate
            index == this.forms.length-1 ? '' : pdf.addPage();
        })
        // file save
        let blob = pdf.output('blob');
        
        pdf.save('test.pdf');
    })
},
/**
 * @description: cut on canvas
 * @param {number} num number of slices 
 * @param {canvas} canvas 
 * @return {array} canvas list
 */
splitCanvas(canvas,num){
    let height = canvas.height,width = canvas.width;
    let chunkHeight = height/num;// the height of each slice
    let chunkList = [];// store the result canvas
    for(let i=0; i<height ; i+=chunkHeight){
        // initialize the crop rectangle box position
        let sx = 0,sy = i,sWidth = width,sHeight = chunkHeight,dx = 0, dy = 0;
        // Create a canvas node
        let canvasItem = document.createElement("canvas");
        // Initialize the canvas size
        canvasItem.height = chunkHeight;
        canvasItem.width = width;
        let cxt = canvasItem.getContext("2d");
        // put the cropped image into the new canvas node
        cxt.drawImage(canvas,sx,sy,sWidth,sHeight,dx,dy,sWidth,sHeight);
        chunkList.push(canvasItem); 
    }
    return chunkList;
},

最終効果

フォームが保存された後のページ

<図

pdfに変換したときの効果

<図

 HTMLからPDFへの純粋なクライアントサイドと純粋なサーバーサイドのソリューションに関するこの記事はこれで終わりです、より関連するHTMLからPDFへのコンテンツは、スクリプトハウスの過去の記事を検索するか、次の関連記事を参照してください、私はあなたが将来的にもっとスクリプトハウスをサポートして願っています!。