Help us understand the problem. What is going on with this article?

クライアントサイドだけで日本語PDFを出力したときの文字化け・改行不具合をpdfmake最新版で再ビルドして直した話

はじめに

  • 常用文字にサブセット化を行ったものを id:naoa_yさんが作ってくれているのでそれを使っても良い
    • ビルド後のファイル(vfs_fonts.js)で 5MB -> 2.3MBぐらいに減ってる
    • ただしbuildが5年前なのでpdfmakeのバージョンが0.1.20と古い
    • 最新は0.1.63 (released this on 11 Dec 2019)
  • 上記のpdfmake@0.1.20だと日本語化したときの文字改行(word wrap)が適切にうごかない&改行されたとき文字化けする不具合があった
    • 私の場合、可変長の文字を動的に組み込む必要があり、自動改行はどうしても必要だった。1行に収まる短文のみであれば問題ないかと
  • 最新だとなおるかもしれないと、pdfmakeを最新にして使いたかったので、buildし直した。結論、治った!
  • Vueと書いてるけど、フォント差し替えるまでは共通だとおもう
  • @watameさんの記事を参考にしました。ありがとうございます。

TL;DR

  • このリポジトリにある、build/pdfmake.min.js, build/vfs_fonts.jsを使えばよいです。2つ合わせると10MB程度になります
  • https://github.com/yazashin/pdfmake/tree/0.1.63-ja
  • フォントサイズを減らしたい・違うフォントにしたいって人は下記を読みましょう

日本語対応pdfmakeをビルドする

fork&cloneする

cloneした後branchを0.1系に切り替える

  • "This is unstable master branch for version 0.2.x, for stable version 0.1.x see branch 0.1."とのこと

日本語フォントを入手する

  • ここは好み・用途によるとおもいますが、私のケースではこのフォントがマッチしました
  • https://ipafont.ipa.go.jp/#jp
  • IPAexゴシックのみ利用(等幅フォント)
  • メリデメを考えた時、メリットが勝ったのでこれを選択
    • 用途として、珍しい漢字もつかわれるのでサブセット化したとき文字化けの発生が怖い
    • pdfmakeとvfs_fontsで合計して10MBぐらいになる
      • pdfmake.min.js 1.2MB / vfs_fonts.js 8.1MB
      • 印刷ページごとに都度読み込みタイプだと辛い印象がある
      • vueのようなSPAでindex.htmlにscriptタグでglobalに登録してしまえば、大きな問題にはならないって考えて進めた
      • ぶっちゃけ最近はネット回線高速なので、SPAで初回ロード時に1回発生する10MB程度ならほとんど気にならないと思う
        • 安定したらServiceWorkerのキャッシュ対象にしてしまうのもありだとおもう
      • SEO気にする必要がない業務系サービスなのでこの判断ができている。っていう前提があります。
        • むしろSEO気にするサービスで、SPA & PDF生成が必要って、かなりニッチだとはおもうけどw

フォントを入れ替える

  • before
    image.png

  • after
    image.png

vfs_fonts.jsの更新

  • buildFontsを実行
$ yarn install
  ....
success Saved lockfile.
✨  Done in 216.37s.

$ ./node_modules/.bin/gulp buildFonts
[10:45:48] Using gulpfile ~/workspace/pdfmake/gulpfile.js
[10:45:48] Starting 'buildFonts'...
[10:45:48] Finished 'buildFonts' after 189 ms
  • pdfmakeへフォントを反映
$ yarn run build
...
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
[10:50:16] Finished 'build' after 23 s
✨  Done in 24.49s.
  • warning出てるけど無視して進める

vfs_fonts.jsの確認

  • buildフォルダにあるvfs_fonts.jsがこうなっていれば大丈夫 build.png

Vue(typescript)で確認

  • 今回つくったpdfmake & vfs_fonts は、npmとして登録はせず、publicなフォルダに静的jsとして利用する
    • npmにするとdeploy時にciでビルドするとき、フォントのビルドから必要になるとか、そこらへん面倒でこうした
  • vue-cliのversionによって構成かわりますが、VUE_PROJECT_DIR/public/static-js/配下においた

index.htmlに登録

  • ポイントして、 deferを忘れずにつけましょう。10MB近いjsの読み込みでHTMLのパースが止まってしまいUXに影響がでます
index.html
 ... ~~~ ...
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
  <script defer src="/static-js/pdfmake.min.js"></script>
  <script defer src="/static-js/vfs_fonts.js"></script>
</html>

Vueの実装

  • Vueで使うときはこんなかんじ。手打ちなので間違ってるかもしれません。
pdf.vue
declare var pdfMake: any;
@Component({})
export default class PrintPdf extends Vue {
    createPdf() {
        pdfMake.fonts = {
            IPA_gothic: {
                normal: 'ipaexg.ttf',
                bold: 'ipaexg.ttf',
                italics: 'ipaexg.ttf',
                bolditalics: 'ipaexg.ttf',
            }
        };
        const defaultStyle = 'IPA_gothic';
        const docDefinition = {
            content: 'Hello 日本語!',
            defaultStyle: {
                font: defaultStyle
            }
        }
        pdfMake.createPdf(docDefinition).print();
    }
}
  • pdfmake 0.1.63 & IPAゴシック で生成したPDF
  • なお、文章はジェネレータでつくったので意味をなしてません。
    image.png

  • 文字改行時の文字化け不具合がなおって本当に良かった..

Thanks

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした