2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Node.js】RustエンジンのPDFライブラリをNode.jsに移植した — プリビルドバイナリ同梱、node-gyp不要、0.8ms

2
Posted at

Node.js向けPDFライブラリをリリースしました

約半年前にpdf_oxide (RustエンジンのPDFライブラリ) をMIT / Apache-2.0で公開しました。最初はRustとPythonだけでしたが、ここ数ヶ月はほぼ毎日のようにフィードバック (バグ報告、パースできないPDF、日本語CIDフォントのエッジケース、ICCカラー、マルチカラムレイアウト検出など) をいただいて、地道に直してきました。

v0.3.5 → v0.3.37の間でかなり安定してきたので、コアが落ち着いたこの2ヶ月でGo、C# / .NET、Node.js / TypeScriptの各言語バインディングを書きました。今回のNode.js / TypeScriptバインディングについて、実際に使ってみたご意見を伺いたく投稿しています。

平均0.8ms、MIT / Apache-2.0ライセンス、node-gyp不要でインストールできます。

インストールと使い方

npm install pdf-oxide
const { PdfDocument } = require("pdf-oxide");

const doc = new PdfDocument("paper.pdf");
const text = doc.extractText(0);
const markdown = doc.toMarkdown(0);
doc.close();

TypeScript:

import { PdfDocument } from "pdf-oxide";

const doc = new PdfDocument("paper.pdf");
const text: string = doc.extractText(0);

型定義 (.d.ts) はパッケージに同梱しています。Node.js 18 / 20 / 22対応、Linux / macOS / Windowsのx64 + ARM64でプリビルドバイナリを配布。インストール時にnode-gypやRustツールチェーンは一切必要ありません。

なぜ作ったか

元々はRustとPythonで使っていたものを、Node.jsからも呼びたくて作りました。Node.jsのPDFライブラリは選択肢が限られていて、以下の不満がありました。

  • pdf-parse — メンテナンスが実質止まっている
  • pdf.js — 本来はブラウザ用なので依存が重い (~10MB)
  • pdf-lib — PDF作成はできるがテキスト抽出はできない

MITライセンスで、AWS Lambdaのコールドスタートで気にならない速度で、.nodeファイルをプリビルドで配布していて、日本語PDFの文字化けが出ない、という条件を全部満たすものが欲しかった、という経緯です。

Linux glibcの話

Node.jsバインディングで一番苦労したのは、プリビルドの.nodeファイルのglibc互換性でした。

GitHub Actionsのubuntu-latestでビルドしたバイナリは、Alpine Kubernetes上のコンテナやAWS Lambda provided.al2023 ランタイムに持っていくと、GLIBC_2.34 not found で起動すら失敗します。実行時にldd --versionが合わないケースで落ちるので、CIは緑なのに本番で落ちるというパターンになりがちです。

対応はシンプルで、centos7時代のglibcをベースラインにしてビルドし直すだけなのですが、CI環境の再構築に1週間ほどかかりました。

v0.3.37時点では、LambdaとAlpine K8sの両方で動作確認済みです。

日本語PDFの対応

Node.jsバインディングもRust / Pythonと同じコアを使っているので、日本語CIDフォント対応もそのまま引き継いでいます。

  • Adobe-Japan1 (15,000+エントリ) のCID-to-Unicodeマッピング内蔵
  • 4言語合計で80,000+マッピング (Japan1 / GB1 / CNS1 / Korea1)
  • Shift-JIS / RKSJデコーディング対応
  • CFFフォントのエンコーディングパーサー実装済み

日本語PDFでの文字化け撲滅についてはQiitaで前に別記事を書いたので、詳しくはそちら (【PDF】日本語PDFの文字化けに怒ってRustでPDFパーサーを書いた) を参照してください。

ベンチマーク

3,830の実PDFファイル (veraPDF 2,907、Mozilla pdf.js 897、DARPA SafeDocs 26) でテスト。全バインディングで同じRustコアを使っているので数字は共通です。

ライブラリ 平均 p99 パス率 ライセンス
pdf_oxide 0.8ms 9ms 100% MIT / Apache-2.0
PyMuPDF 4.6ms 28ms 99.3% AGPL-3.0
pypdfium2 4.1ms 42ms 99.2% Apache-2.0
pdftext 7.3ms 82ms 99.0% GPL-3.0
pdfminer 16.8ms 124ms 98.8% MIT
pdfplumber 23.2ms 189ms 98.8% MIT

Node.jsバインディングのオーバーヘッドは、Rust直接呼び出しに対して実PDFで~25%以内に収まっています。

その他のバインディング

同じ期間にGoとC# / .NETも同時にリリースしました。

# Go
go get github.com/yfedoseev/pdf_oxide/go
go run github.com/yfedoseev/pdf_oxide/go/cmd/install@latest

# C# / .NET
dotnet add package PdfOxide

全バインディング共通で、Rustコア側のメンテナンス (v0.3.34 — v0.3.37) も続けています。ICCカラー管理、マルチカラムレイアウト検出、XY-cut列検出の精度改善など。

残っている課題

  • AES-256暗号化PDFでエッジケースがいくつか残っています
  • テーブル抽出はpdfplumberほど細かくはないです、改善中です

リンク

Node.jsからのAPIは自然でしょうか、型定義に違和感はないでしょうか、あるいは「このユースケースが足りない」など、ご意見をコメントかGitHub issueで教えていただけると助かります。日本語PDFで文字化けするケースもそのまま送っていただければ直します。

2
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?