2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

laravel-dompdfを使用してPDF化を実装してみた【日本語対応】

Last updated at Posted at 2024-04-25

はじめに

webページをPDFでダウンロードできるようにしたいと、実務で要望があったため、今回laravel-dompdfを用いてPDF化を実装してみました。

laravel-dompdfを採用した理由

PDF化を実装できるライブラリは幾つかあり、laravel-dompdfとlaravel-snappyの2つで迷いましたが、以下のメリット・デメリットを比較して、今回はlaravel-dompdfで実装することとしました。

laravel-dompdf

メリット
・導入が簡単である。
・比較的新しいCSSが使用できない。 ⇒flexBoxなど
デメリット
・外部バイナリに依存するため、環境設定が少し複雑である。

laravel-snappy

メリット
・高い互換性と精確なレンダリング
・複雑なデザインやスクリプトが含まれるページでも正確にPDFを生成。
デメリット
・外部バイナリに依存するため、環境設定が少し複雑である。

今回はPDF化したいページのデザインが複雑でもなく、スピード感を求められていたため、laravel-dompdfを採用しました。

実装手順

1. パッケージのインストールをする

まず、laravel-dompdfのパッケージをインストールします。

composer require barryvdh/laravel-dompdf

2. 日本語に対応するため、日本語対応フォントを用意する

laravel-dompdfは、初期設定では日本語は文字化けしてしまいます。そのため日本語対応のフォントを用意する必要があります。

今回は、「Noto Sans Japanese」を使用しました。

ダウンロードした後、/storage/fontsにttfファイルを保存してください。

3. ControllerにPDFダウンロードの処理を書く

PdfController
use Barryvdh\DomPDF\Facade\Pdf;

public function downloadPdf(){
        $pdf = PDF::loadView('/pdf')
                    ->set_option('compress', 1)
                    ->setPaper('a4', 'portrait'); // 縦A4サイズに指定

        $fileName = '領収書.pdf';
        
        return $pdf->download($fileName);
}

4. PDF化するビューを用意する

ここでは例として、領収書のテンプレートを用意しています。

pdf.blade.php
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>領収書</title>
    <style>
        /* 基本の文字 */
        @font-face {
            font-family: 'NotoSansJP';
            font-style: normal;
            font-weight: normal;
            src: url('{{ storage_path('fonts/NotoSansJP-Regular.ttf') }}');
        }
        /* 全てのHTML要素に適用 */
        html, body, textarea, table {
            font-family: 'NotoSansJP', sans-serif;
        }
        body {
            padding-top: 5mm;
            width: 190mm;
            height: 297mm;
            margin-left: auto;
            margin-right: auto;
            font-size: 12px;
        }

        .header,
        .footer {
            width: 100%;
            overflow: hidden;
        }

        .left,
        .right {
            width: 48%;
            box-sizing: border-box;
        }

        .left {
            float: left;
        }

        .right {
            float: right;
            text-align: right;
        }

        .clearfix:after {
            content: "";
            display: table;
            clear: both;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }

        table,
        th,
        td {
            border: 1px solid #000;
        }

        th,
        td {
            padding: 8px;
            text-align: left;
        }

        th {
            background-color: #f2f2f2;
        }

        .total {
            text-align: right;
            margin-top: 10px;
        }
    </style>
</head>

<body>
    <p style="font-size:22px; text-align:center; margin-top: 5px; margin-bottom: 5px;">領収書</p>
    <div class="header clearfix">
        <div class="left">
            <p>
                〇〇 〇〇様
            </p>
        </div>
        <div class="right">
            @php($date = new \Carbon\Carbon($order->created_at))
            <p>注文日:〇月〇日</p><br>
            <p>
                株式会社〇〇<br>
                〒〇〇〇-〇〇〇〇<br>
                東京都〇〇〇〇<br>
                登録番号:〇〇〇〇<br>
            </p>
        </div>
    </div>
    <div style="border-top: 1px solid #000; border-bottom: 1px solid #000; text-align:center;">
        <div>
            <p style="font-size: 16px;">合計金額 ¥〇〇円</p>
        </div>
    </div>
    <div>
        <div>
            <p>上記、正に領収いたしました。</p>
        </div>
    </div>
    <div>
            <p style="margin: 0;">【サービス料金内訳】</p>
    </div>
    <TABLE class="price" style="margin-top: 0;">
        <TR>
            <Th style="font-weight:normal;">サービス項目</Th>
            <Th style="font-weight:normal;">単価</Th>
            <Th style="font-weight:normal;">時間</Th>
            <Th style="font-weight:normal;">数量</Th>
            <Th style="font-weight:normal;">金額(税抜)</Th>
            <Th style="font-weight:normal;">金額(税込)</Th>
            <Th style="font-weight:normal;">消費税</Th>
        </TR>
        <TR>
            <TD>〇〇</TD>
            <TD>〇〇</TD>
            <TD>〇〇</TD>
            <TD>〇〇</TD>
            <TD>〇〇</TD>
            <TD>〇〇</TD>
            <TD>10%</TD>
        </TR>
    </TABLE>
    <div class="header clearfix" style="border-top: 1px solid #000; border-bottom: 1px solid #000;">
        <div class="left">
            <p style="font-size: 14px; margin:0;">合計金額(税抜)</p>
            <p style="font-size: 14px; margin:0;">合計金額(消費税額)</p>
            <p style="font-size: 14px; margin:0;">合計金額(税込)</p>
        </div>
        <div class="right">
            <p style="font-size: 14px; margin:0;">〇〇円</p>
            <p style="font-size: 14px; margin:0;">〇〇円</p>
            <p style="font-size: 14px; margin:0;">〇〇円</p>
        </div>
    </div>
</body>
</html>

5. ファイルサイズを小さくする処理を追加する。

これで日本語でPDFとしてダウンロードできるようになりましたが、ファイルサイズが3.5MBほどと大きくなってしまっています。

これは追加した日本語フォントがすべて組み込まれてしまっているため、ファイルサイズを圧迫しています。

そのため、dompdfの設定ファイルに設定を変更しましょう。

設定ファイルを以下のコマンドで作成します。

php artisan vendor=publish --provider="Barryvdh"

これでconfigフォルダに「dompdf.php」が作成されたと思います。

dompdf.php内の以下の値を「true」に変更してください。

"enable_font_subsetting" => true

さいごに

パッケージを使用すると、簡単にPDF化できるので、今後も使っていきたいと思います。
また今回は採用しなかったlaravel-snappyを使用したPDF化も時間がある際に実装してみたいと思います。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?