はじめに
PDF内の文章をアプリで入力し、生成できる系アプリのお話。
ユーザーが沢山PDFを生成できる条件であればよりコストを抑えるためにファイルサイズを落としてデータ転送量やストレージ使用量を抑えたいですよね・・・
PDFのファイルサイズはただ圧縮するだけが方法ではないことに気づいたので記事にしました。
PDFで何をしたかったか
・日本語を表示するPDFの新規作成したい
実装してみると
ライブラリを使用して日本語の書き込みをしたPDFを生成するだけの簡単なお仕事に見えますが、ちょっとした落とし穴があります。
今回はPDF-LIBを使用していますが、デフォルトで日本語がサポートされておらず日本語が正しく書き込みされません。
そのため、自分でフォントを用意してPDFに埋め込みをする必要性があります。
◻︎日本語フォントを埋め込みした場合の実装は以下の通り
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
import fs from 'fs'; // Node.js環境用(ブラウザではfetchを使用)
async function createPDF() {
// 新しいPDFドキュメントを作成
const pdfDoc = await PDFDocument.create();
// ページを追加
const page = pdfDoc.addPage([600, 400]);
// カスタムフォントを埋め込む(例: Noto Sans JP)
const fontBytes = fs.readFileSync('NotoSansJP-Regular.otf'); // フォントファイルを読み込む
const customFont = await pdfDoc.embedFont(fontBytes);
// 書き込み
page.drawText('こんにちは', {
x: 50,
y: 300,
size: 20,
font: customFont,
color: rgb(0, 0.5, 0),
});
// PDFを保存
const pdfBytes = await pdfDoc.save();
fs.writeFileSync('output.pdf', pdfBytes);
}
createPDF().then(() => console.log('PDF Created!')).catch(console.error);
フォントを埋め込む一手間があったとはいえ簡単ですね!
ここで問題が発生
「こんなシンプルなPDFなのにファイルサイズが大きすぎる...!?』
こんなことが発生しました。(10MBくらい)
私が最初にこの問題へ遭遇したときは、ベースとなるPDFが別にありそれに大量に文字の書き込みや画像の埋め込みをしていたため、ベースのPDFのファイルサイズを小さくしたり、圧縮を検討したりなどして苦戦しておりました(ライブラリさん、あんたが悪いんか…? とか)
結局何が悪かったか
先に示したコードから分かる通り、PDFに対して埋め込んでいるのは「こんにちは」の文字とフォント
です。
フォントは必要不可欠なものですが、フォントのサイズがしっかりとPDFのファイルサイズに直結しております。
過去に多言語対応したフォント(18MBくらい)を使用した際は、PDFのファイルサイズもそれに近いものとなりました。
サブセット化による解決
今回この問題を解決するためにサブセット化(フォントの軽量化)をしていきます。
つまりは、使用することが期待されない文字もフォントに含まれているのでそれを削ぎ落としてフォントのファイルサイズを減らすということです。
サブセット化を行うために、サブセットフォントメーカーといったツールがあり、フォントファイルと残しておきたい文字をインプットとして与えると、その文字だけの軽量化されたフォントが生成されます。
ここで気をつける必要性があるのは、使用が期待される文字をしっかり予測しておかないと文字化けが起きてしましますので、気をつけて行いましょう。
私の場合はベトナム人やネパール人の使用ケースに対応させる必要性があり、言語の理解をするイベントが発生。
※『नमस्ते』 何これ、難しい・・・
漢字も数は膨大でどこまで対応させるかを検討する必要性があり地味に大変なお仕事です。
フォントの世界で日本語など漢字を扱う言語は大変だろうなと実感しました。
最後に
今回、なかなか気づけなかった原因として日本語を書き込むためにフォントは当然必要なもので思考が止まっていたこと、PDF書き込みの機能を作り上げた後で「サイズ大きい!?」となってしまったため問題点に気づくのが遅くなりました。
ファイルサイズはコスト面やユーザー体験的にも致命傷になりかねないので、アンテナを常に張りながら開発をしていきたいと思ったといった記事でした。