tag:crieit.net,2005:https://crieit.net/users/hand-dot/feed hand-dotの投稿 - Crieit Crieitでユーザーhand-dotによる最近の投稿 2020-09-25T02:56:46+09:00 https://crieit.net/users/hand-dot/feed tag:crieit.net,2005:PublicArticle/16071 2020-09-25T02:54:21+09:00 2020-09-25T02:56:46+09:00 https://crieit.net/posts/Javascript-PDF JavascriptでPDFを作成するライブラリまとめと比較 <p><a href="https://crieit.now.sh/upload_images/72b6800e676458962e78520f80fde1905f6cdddc140c5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/72b6800e676458962e78520f80fde1905f6cdddc140c5.png?mw=700" alt="image" /></a><br /> はじめまして。<br /> <a target="_blank" rel="nofollow noopener" href="https://labelmake.jp/">PDFの作成サービス</a>を個人で運用しており、数万ページのPDFを作成しており、<a target="_blank" rel="nofollow noopener" href="https://github.com/hand-dot/labelmake">JavascriptでのPDFの作成ライブラリ</a>を作ったりでそれなりに詳しくなってきたのでこの記事を作成しました。笑</p> <p>Javascriptで扱えるPDFのライブラリーはいくつかあります。しかし、実際どれを使えばいいのかわかりにくいので、それらを比較しながら紹介していきます。</p> <p>UMDモジュールとして提供されていて、近年のフロントエンド(TypeScript/Webpack/React/etc.)で扱いやすい?Nodeとブラウザーで動く?型はあるか?日本語フォントは使えるのか?という観点でも比較していきます。</p> <p><strong>この記事ではJavascriptで扱えるPDF作成ライブラリーで「どれを採用するか」ということで悩んでいる時に、用途に合ったライブラリを発見することができるようにします。</strong></p> <h2 id="PDFKit"><a href="#PDFKit">PDFKit</a></h2> <p><a href="https://crieit.now.sh/upload_images/287fd18c57a76a8f56e19136fce9d4bb5f6cda03acf7b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/287fd18c57a76a8f56e19136fce9d4bb5f6cda03acf7b.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="https://pdfkit.org/">公式サイト:https://pdfkit.org/</a></p> <p><strong>PDFKitはJavascriptでPDFを作成するライブラリの元祖的存在。</strong> フォントの埋め込みや画像の埋め込みもできます。開発が2012年から行われており古いですが、今でもメンテナンスが行われております。多少複雑ですがNodeだけでなく、 <a target="_blank" rel="nofollow noopener" href="https://github.com/foliojs/pdfkit#browser-usage">Webpackを利用してブラウザで動かすことも可能です。</a></p> <p>下記に紹介するライブラリでもPDFKitのラッパーとして作成されたものや、プログラムを参考にしているものもあり、フォントの埋め込みも含めてJavascriptでPDF作成を行うというパワープレーを最初に成し遂げたライブラリと言うだけあってすごいライブラリです。</p> <p>よくない点をあげるなら、高レベルのAPIを提供していないで操作に慣れるまでに一定の学習が必要です。最初はデザインがしづらく、記述が複雑になりがちです。</p> <div class="table-responsive"><table> <thead> <tr> <th>ポイント</th> <th>評価</th> </tr> </thead> <tbody> <tr> <td>Nodeとブラウザーで動く</td> <td>△(若干手間)</td> </tr> <tr> <td>型はあるか</td> <td>○(DefinitelyTyped)</td> </tr> <tr> <td>日本語フォントは使えるのか</td> <td>○(ブラウザで使う場合は要注意)</td> </tr> <tr> <td>使いやすさ</td> <td>△プログラムの手続きが複雑</td> </tr> </tbody> </table></div> <hr /> <h2 id="pdfmake"><a href="#pdfmake">pdfmake</a></h2> <p><a href="https://crieit.now.sh/upload_images/2647ea287bd70147a7e7f1bc0ef4fe4e5f6cda73ce101.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/2647ea287bd70147a7e7f1bc0ef4fe4e5f6cda73ce101.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="http://pdfmake.org/">公式サイト:http://pdfmake.org/</a></p> <p><strong>上記で紹介したPDFKitのラッパーとして作成されたのがpdfmakeです。 PDFKitとの違いはPDFKitが命令的なプログラミング操作のAPIを提供しているのに対して、pdfmakeは宣言的でレイアウトによる計算をpdfmakeが行ってくれるためプログラムが比較的少なくなります。</strong></p> <p>PDFKitの改良版としてGithubでのスター数はpdfmakeの方が多く、Web上でも様々な使い方や例があり、人気のライブラリということがわかります。また、画像の埋め込みはもちろん、QRコード,SVGのレンダリングなどの機能もあります。</p> <p>実際にPDFkitと比較した時にその使いやすさから本サービスのlabelmake.jpも当初はpdfmakeを利用してPDFファイルを作成しておりました。</p> <p>しかし、</p> <ul> <li>独自フォントの作成し、利用する時にWebpack利用時にハマりどころがある</li> <li>独自フォントはbase64エンコードされたttfが利用できるが日本語フォントの場合に巨大になり、メモリを大量に消費する</li> </ul> <p>と言う点がネックになり、途中で後で紹介するpdf-libというものに切り替えています。</p> <p>Web上には様々な例があるため、トライアンドエラーを繰り返しながらなんとかなるとは思いますが、Webpackやtypescriptを使った最新のフロントエンドではハマりどころが多く、その手の記事が無かったりするので注意が必要です。 また、日本語フォントを利用する際は一度gitのrepositoryをクローンしてからフォント作成スクリプトを使ってビルドする必要があります。</p> <div class="table-responsive"><table> <thead> <tr> <th>ポイント</th> <th>評価</th> </tr> </thead> <tbody> <tr> <td>Nodeとブラウザーで動く</td> <td>△(Webpackなどを利用している場合はハマる)</td> </tr> <tr> <td>型はあるか</td> <td>○(DefinitelyTyped)</td> </tr> <tr> <td>日本語フォントは使えるのか</td> <td>△(自前でビルドが必要)</td> </tr> <tr> <td>使いやすさ</td> <td>○(宣言的でpdfmakeのレイアウトエンジンが利用可能)</td> </tr> </tbody> </table></div> <hr /> <h2 id="jsPDF"><a href="#jsPDF">jsPDF</a></h2> <p><a href="https://crieit.now.sh/upload_images/cfed57cc5b84c8c2d1910334c10275fd5f6cda89bd93d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/cfed57cc5b84c8c2d1910334c10275fd5f6cda89bd93d.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/MrRio/jsPDF">公式サイト:https://github.com/MrRio/jsPDF</a></p> <p><strong>jsPDFは上記のPDFKitとは別に独自にPDF作成ができるライブラリです。 この記事で紹介するライブラリの中で一番スター数が多く、比較的安定してメンテナンスされています。</strong></p> <p>node,ブラウザーで利用できるUMDモジュールも提供されています。(nodeで保存する場合はカレントディレクトリに保存されるので使い勝手悪いかもです)</p> <p>命令的な操作ができるAPIが提供されており、複雑な帳票をプログラムする場合は難易度が高い印象です。</p> <p>また、日本語を扱う場合は日本語のフォントを読み込ませる必要がありますが、ここにハマりどころがあるようです。<br /> 詳細は下記の記事にまとまっています</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/JunichiWatanuki/items/07bcb842e5532068fd62">jsPDFで、無理やり日本語出力を行ってみる </a></li> <li><a target="_blank" rel="nofollow noopener" href="https://blog.ver001.com/javascript-jspdf-japanese/">JavaScriptでjsPDFを使ってPDFファイルを生成する(日本語対応)</a></li> </ul> <p>上記を参考にしていただければわかりますが、日本語フォントを扱うための方法はありますが、一手間必要になります。(ttfファイルの変換が必要)</p> <p>できることは多いのですが、上記で説明したように操作が命令的でなため、使いこなすには一定のインプットが必要になります。(幸いにもリッチなドキュメントがあります <a target="_blank" rel="nofollow noopener" href="https://rawgit.com/MrRio/jsPDF/master/docs/index.html">https://rawgit.com/MrRio/jsPDF/master/docs/index.html</a>)<br /> また、英語の記事も多く人気なのは間違いないと思います。</p> <p>ドキュメントを参考にして自分の用途に合った操作ができる場合はおすすめできます。(ドキュメントみた感じだとAcroFormとかできちゃいます。ヤバイな)</p> <div class="table-responsive"><table> <thead> <tr> <th>ポイント</th> <th>評価</th> </tr> </thead> <tbody> <tr> <td>Nodeとブラウザーで動く</td> <td>○(<a target="_blank" rel="nofollow noopener" href="https://github.com/MrRio/jsPDF#typescriptangularwebpackreactetc-configuration">参考</a>)</td> </tr> <tr> <td>型はあるか</td> <td>○</td> </tr> <tr> <td>日本語フォントは使えるのか</td> <td>○(ttfファイルの変換が必要)</td> </tr> <tr> <td>使いやすさ</td> <td>△プログラムの手続きが複雑</td> </tr> </tbody> </table></div> <hr /> <h2 id="pdf-lib"><a href="#pdf-lib">pdf-lib</a></h2> <p><a href="https://crieit.now.sh/upload_images/aeb78cf46f1fadacd773efbc17dc76e35f6cdaa3bde4f.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/aeb78cf46f1fadacd773efbc17dc76e35f6cdaa3bde4f.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="https://pdf-lib.js.org/">公式サイト:https://pdf-lib.js.org/</a></p> <p><strong>pdf-libはPDFKitを参考にTypescriptで実装されたPDFの作成、編集ライブラリです。 他のライブラリに比べて後発でリリースされたライブラリですが、非常によくできており、もちろんnode,ブラウザで動作します。また、PDFの結合、分割や埋め込みをサポートし、他のライブラリにない機能を持っていますが、ライブラリとしてシンプルで強力です。</strong></p> <p><strong>他のライブラリと比較して大きく違う点がフォントファイルを埋め込む際に<code>Uint8Array</code>,<code>ArrayBuffer</code>が使用できる</strong>ので、nodeの場合は<code>fs</code>で、ブラウザの場合は<code>xhr</code>を使ってフォントファイルを読み込むことができます。日本語の馬鹿でかいbase64のファイルを読み込む必要がなくなり、パフォーマンス的にも優れています。</p> <p>もちろん、Webpackなどで利用でき、ドキュメントも充実しています。 本サービスのlabelmake.jpも当初はpdfmakeを利用していましたが、途中からパフォーマンスの観点でPDF作成処理をpdf-libに行わせるよう変更しました。</p> <p>欠点としては提供されているAPIが命令的なため複雑な帳票の場合、プログラムが複雑になってしまうという点と考えています。また<strong>レイアウトについてはpdf-libは責務を持たず、ユーザーに計算させるという方針ですので、中央揃えや右揃えなどのレイアウトはできません。</strong>あと地味ですが、位置情報の単位が<code>pt</code>なので、位置を指定する時に若干面倒です。</p> <p>個人的には後に紹介するlabelmakeを除くライブラリに比べて一番扱いやすく、パフォーマンスの観点でも優秀だと考えています。</p> <p>まだ日本語での記事数はpdfmake,jsPDFと比べると少ないのですが、帳票が比較的シンプルでモダンな環境での開発の場合は参考にしてみてください。おすすめです。</p> <div class="table-responsive"><table> <thead> <tr> <th>ポイント</th> <th>評価</th> </tr> </thead> <tbody> <tr> <td>Nodeとブラウザーで動く</td> <td>○</td> </tr> <tr> <td>型はあるか</td> <td>○</td> </tr> <tr> <td>日本語フォントは使えるのか</td> <td>○</td> </tr> <tr> <td>使いやすさ</td> <td>△プログラムの手続きが複雑+レイアウトの計算は自分で行う必要がある</td> </tr> </tbody> </table></div> <hr /> <h2 id="labelmake"><a href="#labelmake">labelmake</a></h2> <p><a href="https://crieit.now.sh/upload_images/c2fcbd38933cf75273dc378858f1da235f6cdab902f0f.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c2fcbd38933cf75273dc378858f1da235f6cdab902f0f.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="https://labelmake.jp/javascript-pdf-generator-library">公式サイト:https://labelmake.jp/javascript-pdf-generator-library</a></p> <p><strong>labelmakeはpdf-libのラッパーとして筆者が開発しました。 特徴としてはpdf-libを使っている人はレイアウトは自分で計算する必要がありましたが、位置情報の単位をmmにし、alignment,line-heightなどのレイアウトの計算を行い、宣言的にデータでPDFを作成できるようにAPIをデザインしました。</strong> また既存のPDFをベースとして読み込んでそこに入力項目を足すことができます。</p> <p>コードの例は<a target="_blank" rel="nofollow noopener" href="https://labelmake.jp/javascript-pdf-generator-library/example">こちらからご覧になれます。</a><br /> スキーマがあるので、テンプレート的に帳票生成などに利用ができます。</p> <p>帳票のデザインデータをJSONで管理できる点も複数のテンプレートを利用する際には読み込みがシンプルになり利用しやすいです。</p> <p>pdf-libのメリットのフォントのデータで<code>Uint8Array</code>,<code>ArrayBuffer</code>が使用できる点や、PDFファイルの埋め込みができる点を利用して効率的に複雑な帳票が作成できるようにしています。</p> <p><strong>また、<a target="_blank" rel="nofollow noopener" href="https://labelmake.jp/javascript-pdf-generator-library/template-design">こちらのTemplate Design & Code Generator</a>を使い、帳票のデザインと、実行可能コードの生成を行うことができます。</strong></p> <p><a href="https://crieit.now.sh/upload_images/fa948ee1c0bf1cf7c5b8b90d55e0e6f15f6cdad97418f.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/fa948ee1c0bf1cf7c5b8b90d55e0e6f15f6cdad97418f.png?mw=700" alt="image" /></a></p> <p>ポジショントークにならないようにしたいと思いますが、既存のPDFファイルに対して入力項目を設定する形で帳票が作成でき、実際に本サービスでは現時点で様々なテンプレートをつかってPDFを作成しています。</p> <p>デメリットとしてはまだ利用者も少なく、有名なライブラリではありません。<br /> 日本語フォントで利用していますが、他にも自分のサービスだけでは見つけられなかったバグがあるかもしれません。</p> <p><strong>そして、自由に0から帳票すると言うよりは既存のPDFをもとに入力項目を設置するという使い方がハマります。(俗に言うバリアブル印刷というやつです)<br /> 他のJavascriptのPDF作成ライブラリと比較しても、用途が合っている場合は、我ながらよくできていると思っていますので、ぜひスターやシェアをしていただけると嬉しいです 笑</strong></p> <div class="table-responsive"><table> <thead> <tr> <th>ポイント</th> <th>評価</th> </tr> </thead> <tbody> <tr> <td>Nodeとブラウザーで動く</td> <td>○</td> </tr> <tr> <td>型はあるか</td> <td>○</td> </tr> <tr> <td>日本語フォントは使えるのか</td> <td>○</td> </tr> <tr> <td>使いやすさ</td> <td>○</td> </tr> </tbody> </table></div> <hr /> <h2 id="番外編"><a href="#%E7%95%AA%E5%A4%96%E7%B7%A8">番外編</a></h2> <h3 id="PDF.js"><a href="#PDF.js">PDF.js</a></h3> <p><a href="https://crieit.now.sh/upload_images/d4c455428e1bc1bcb7f22658c09c4adb5f6cdaf202c18.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/d4c455428e1bc1bcb7f22658c09c4adb5f6cdaf202c18.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="https://mozilla.github.io/pdf.js/">公式サイト:https://mozilla.github.io/pdf.js/</a></p> <p>よく間違えられるのですが、非常に有名なライブラリなので紹介します。<br /> PDF.jsはPDFのレンダリングライブラリで、PDFの作成ライブラリではありません。<br /> PDFを表示するだけでなく、PDFのレンダリング結果をcanvasに転写し、PDFのレンダリング画像を取得することができます。</p> <p>Webpack用のビルドもバンドルされており、最近のフロントエンドの環境でも利用可能です。</p> <hr /> <h3 id="Puppeteer"><a href="#Puppeteer">Puppeteer</a></h3> <p><a href="https://crieit.now.sh/upload_images/6fc4effa9a96db29ebd3ba9a1351a1ae5f6cdb0ba9c4e.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6fc4effa9a96db29ebd3ba9a1351a1ae5f6cdb0ba9c4e.png?mw=700" alt="image" /></a></p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/puppeteer/puppeteer">公式サイト:https://github.com/puppeteer/puppeteer</a></p> <p>GoogleのPuppeteerでもPDFファイルの作成が可能です。<br /> テンプレートはhtmlとして管理する必要がありますが、Webの開発者なら装飾も行いやすいかと思います。</p> <p>実装は下記の記事が参考になります。<br /> - <a target="_blank" rel="nofollow noopener" href="https://dev.to/damcosset/generate-a-pdf-from-html-and-back-on-the-front-5ff5">Generate a PDF from HTML with puppeteer<br /> </a><br /> - <a target="_blank" rel="nofollow noopener" href="https://uyamazak.hatenablog.com/entry/2018/02/08/192304">Headless Chrome + puppeteerを使ったHTML→PDF変換サーバーを作る puppeteer編</a></p> <p>バックエンドの実装が必要になるのと、PDF作成するまでにPuppeteerが起動するオーバーヘッドがありますが、それらが問題ない場合で、htmlでデザインしたいと言う場合には選択肢になるかもしれません。(可変のテーブルなどはデザインしやすいかと思います。)</p> <hr /> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>番外編を除く下記の5つのライブラリを紹介させていただきました。</p> <ol> <li>PDFKit</li> <li>pdfmake</li> <li>jsPDF</li> <li>pdf-lib</li> <li>labelmake</li> </ol> <p>参考になったでしょうか?<br /> 筆者はpdf-lib押しです。パフォーマンスも良く、レイアウトの計算が面倒ですがモダンなフロントエンド環境でも使いやすいです。</p> <p>あとは、遊びでも構わないのでlabelmakeを触っていただけると嬉しいです!</p> <h4><a target="_blank" rel="nofollow noopener" href="https://labelmake.jp/javascript-pdf-generator-library">Webページはこちらからご覧いただけます!</a></h4> <p>それでは!</p> hand-dot