CodeBox CodeBox

Nuxt (Vue.js) × pdfmakeで日本語のPDFを出力する方法

Vue / Nuxt
けい

概要

Nuxt.jsとpdfmakeを使って、クライアントサイドでPDFを出力する方法について解説していきます。Nuxt.jsを使ったものや日本語フォントの読み込みについて紹介している記事がほぼなかったので、ぜひ本記事を参考にしてください!

Nuxt.jsのインストールはこちら
pdfmakeのドキュメントはこちら

pdfmakeを使う準備をしよう

1.pdfmakeをインストール

まずはpdfmakeをnpmでインストールするため、下記コマンドを実行します。package.jsonに反映されていれば成功です。

npm install pdfmake

# package.json
  "dependencies": {
    "pdfmake": "^0.2.2" ← これ(versionは各々の環境で変わります)
  },


2.pluginsフォルダでpdfmakeを読み込む

Nuxtプロジェクト直下(componentsフォルダと同階層)に「pugins」フォルダを作成し、さらにその中に「pdfmake.js」ファイルを作ります。pdfmake.jsには、下記内容を貼り付けてください。

import Vue from 'vue';
import pdfMake from 'pdfmake';


if (process.client) {
  Vue.component('pdfMake', pdfMake);
}


3.nuxt.configでpluginを読み込む

nuxt.config.jsのpluginsの項目に貼り付けてください。ここまでで1通りの設定は完了です。

plugins: [
  { src: "~/plugins/pdfmake.js", mode: "client" }, ← これを貼り付ける
],


4.日本語フォントをダウンロードする

pdfmakeはデフォルトで英語のみ使用可能なので、日本語を使うと文字化けしてしまいます。そこで、日本語フォント(Genshin)のファイルをこちらからダウンロードします。

日本語フォントは「GenShinGothic-Normal.ttf」と「GenShinGothic-Bold.ttf」をサブセット化(不要なものを省く)したもので、元々は8MBぐらいあったのを2MBぐらいに圧縮しています。

ttf形式のフォントをpdfmakeを使って、JS形式に変換する方法はこちらからお願いします。次にNuxtプロジェクトのstaticフォルダに、「vfs_fonts.js」ファイルを作成し先程コピーしておいたコードを貼り付けます。

PDFを出力してみよう

pdfmakeの設定は終わったので、次はPDFを出力してみましょう。ボタンを押すと、別タブでPDFが開くようにしてみます。
image1
「Tutorial.vue」というファイルを作り、下記コードを書きました。

pdfmakeで使う要素はこちら

<template>
  <button
    @click="outputPDF"
    style="
      padding: 10px 20px;
      margin: 10px;
      background-color: blue;
      color: white;
    "
  >
    PDFを出力する
  </button>
</template>


<script>
/* 日本語フォントを読み込む */
import pdfFonts from "~/static/vfs_fonts";

export default {
  methods: {
    outputPDF() {
      pdfMake.vfs = pdfFonts.pdfMake.vfs;
      pdfMake.fonts = {
        GenShin: {
          normal: "genshin-normal.ttf",
          bold: "genshin-bold.ttf",
        },
        English: {
          normal:
            "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Regular.ttf",
          bold: "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Roboto/Roboto-Medium.ttf",
        },
      };

      const defaultStyle = "GenShin";

      const docDefinition = {
        defaultStyle: {
          font: defaultStyle, /* デフォルトの文字を日本語に設定 */
        },
        content: [
          "これは日本語のテストです",
          {
            columns: [
              {
                width: "auto",
                text: "カラム1",
              },
              {
                width: "*",
                text: "カラム2",
              },
              {
                width: 100,
                text: "カラム3",
              },
              {
                width: "20%",
                text: "カラム4",
              },
            ],
            columnGap: 10,
          },
        ],
      };
      pdfMake.createPdf(docDefinition).open(); /* PDFのプレビューを別タブで開く */
    },
  },
};
</script>


別タブに下画像のように表示されれば成功です。日本語も文字化けせずに表示されています。


pdfmakeで画像を表示する - image編 -

pdfmakeで画像を表示する方法を解説します。

①base64形式で画像を読み込む方法

画像は基本的にbase64形式に変換する必要があるので、こちらのサイトで変換しましょう。

今回はunsplashのこちらの画像を使用します。

const docDefinition = {
  content: [
      {
          image: "ここに変換した結果を貼り付けます",
          width: 100,  // 画像のサイズ
        }
   ]
}
pdfMake.createPdf(docDefinition).open();

PDFを出力すると、このような結果となります。

sample

②画像をURLで読み込む方法

base64形式で画像を読み込むと、画像の情報が膨大になり非常にコードが読みづらくなってしまいます。ここではassets配下の画像をXMLを使い、URL化して読み込む方法を紹介します。

export default {
  methods: {
    toDataURL(url, callback) {
      let xhr = new XMLHttpRequest();
      xhr.onload = () => {
        let reader = new FileReader();
        reader.onloadend = () => {
          callback(reader.result);
        };
        reader.readAsDataURL(xhr.response);
      };
      xhr.open("GET", url);
      xhr.responseType = "blob";
      xhr.send();
    },

    outputPDF() {
      this.toDataURL(require("~/assets/images/sample.jpeg"), (dataUrl) => {
        const docDefinition = {
          content: [{ image: dataUrl, width: 500 }],
        };
        pdfMake.createPdf(docDefinition).open();
      });
    },
  },
};


先ほどのbase64形式で読み込むよりもコードがすっきりしました。

pdfmakeでテーブルを表示する - table -

pdfmakeで表(table)を表示することもできます。

const docDefinition = {
  content: [
    {
      table: {
        widths: [100, "40%", "*"],  // 左から順番に100px , 40% , auto
        body: [
          [
            { text: "名前" },
            { text: "メールアドレス" },
            { text: "年齢" },
          ],
          [{ text: "Mike" }, { text: "mike@gmail.com" }, { text: "27" }],
          [{ text: "Ami" }, { text: "ami@gmail.com" }, { text: "21" }],
        ],
      },
    },
  ],
};
pdfMake.createPdf(docDefinition).open();



tableの枠線を無くす&枠線の色を変える方法

borderColorプロパティに白色を指定すると表の枠線を消すことができます。

const docDefinition = {
  content: [
    {
      table: {
        widths: [100, "40%", "*"],
        body: [
          [
            {
              text: "名前",
              borderColor: ["#ffffff", "#ffffff", "#ffffff", "#ffffff"],
            },
            {
              text: "メールアドレス",
              borderColor: ["#ffffff", "#ffffff", "#ffffff", "#ffffff"],
            },
            {
              text: "年齢",
              borderColor: ["#ffffff", "#ffffff", "#ffffff", "#ffffff"],
            },
          ],
        ],
      },
    },
  ],
};
pdfMake.createPdf(docDefinition).open();


tableの余白感(padding)を変える方法

tableのpaddingはlayoutプロパティに、下記のように「paddingTop」と「paddingBottom」を指定するだけです。

content: [
  {
    layout: {
      paddingTop: function (i, node) {
        return 30;
      },
      paddingBottom: function (i, node) {
        return 10;
      },
    },
    table: {
      widths: [100, "40%", "*"],
      body: [
        [
          {
            text: "名前",
          },
          {
            text: "メールアドレス",
          },
          {
            text: "年齢",
          },
        ],
      ],
    },
  },
],
};
pdfMake.createPdf(docDefinition).open();



tableに動的なデータを入れる方法

tableの中に動的なデータを入れる方法も紹介します。

// ダミーデータ
const users = [
  { name: "John", email: "john@gmail.com", age: 27 },
  { name: "Ami", email: "ami@gmail.com", age: 21 },
  { name: "Mike", email: "mike@gmail.com", age: 32 },
];

// 使用するデータの形を整える
const userArray = users.map((user) => {
  return [{ text: user.name }, { text: user.email }, { text: user.age }];
});


const docDefinition = {
  defaultStyle: {
    font: defaultStyle,
  },
  content: [
    {
      table: {
        widths: ["*", "*", "*"],
        body: [
          [
            {
              text: "名前",
            },
            {
              text: "メールアドレス",
            },
            {
              text: "年齢",
            },
          ],
          ...userArray, // 動的なデータを読み込む
        ],
      },
    },
  ],
};
pdfMake.createPdf(docDefinition).open();
},

ABOUT ME

けい
ベンチャーのフロントエンジニア。 主にVueとTypescriptを使っています。ライターのための文字数カウントアプリ:https://easy-count.vercel.app/