DartでPDFを解析!dart_pdf_reader

DartやFlutterでPDFを扱うアプリケーションを開発していると、PDFファイルの内部構造をプログラムから読み取りたいケースがあります。

例えば、

  • PDFファイルを解析する
  • PDFのページ情報を取得する
  • PDFのアウトラインを取得する
  • PDFのコンテンツストリームを読み取る
  • PDF内部のオブジェクトを扱う
  • PDF解析ツールを作る

といった用途です。

今回紹介するdart_pdf_readerは、DartでPDFファイルを解析するためのPure Dartライブラリです。

PDFを画面に表示するためのビューアーではなく、PDFファイルからデータを読み取り、PDFの構造を扱うことを目的としています。

2026年8月時点の最新安定版は2.2.0で、Dart 3.0以上に対応しています。

この記事では、dart_pdf_readerの基本的な使い方から、PDFParser、PDFDocument、ページ、アウトライン、PDFオブジェクト、ストリームなどについて解説します。

dart_pdf_readerとは?

dart_pdf_readerは、PDFファイルを解析するためのPure Dartライブラリです。

パッケージ自体は「多くの解釈を行わないシンプルなPDFリーダー」という位置付けで、PDFファイルからデータを読み取るための仕組みを提供しています。

基本的な処理の流れは以下のようになります。

PDFファイル
    ↓
RandomAccessStream
    ↓
PDFParser
    ↓
PDFDocument
    ↓
Catalog
    ↓
Pages / Outlines

PDFを単純に表示するのではなく、PDFそのものを解析して内部の情報を扱いたい場合に向いています。

dart_pdf_readerの特徴

主な特徴は以下の通りです。

機能対応
PDF解析
Pure Dart
バイト列からの読み込み
ファイルからの読み込み
RandomAccessStream
PDFParser
PDFDocument
ページ情報の取得
アウトラインの取得
コンテンツストリームの取得
PDFオブジェクトの解析
Web
Android
iOS
Linux
macOS
Windows

インストール

pubspec.yamlに追加します。

YAML

dependencies:
  dart_pdf_reader: ^2.2.0

追加したら、以下を実行します。

Bash

flutter pub get

コードから利用する場合はインポートします。

Dart

import 'package:dart_pdf_reader/dart_pdf_reader.dart';

基本的な使い方

dart_pdf_readerでPDFを解析する基本的な流れは非常にシンプルです。

  1. RandomAccessStreamを作成する
  2. PDFParserを作成する
  3. parse()でPDFを解析する

例えば、PDFファイルをバイト列として読み込む場合は以下のようにします。

Dart

import 'dart:io';

import 'package:dart_pdf_reader/dart_pdf_reader.dart';

Future<void> main() async {
  final inputFile = 'sample.pdf';

  final stream = ByteStream(
    File(inputFile).readAsBytesSync(),
  );

  final doc = await PDFParser(stream).parse();

  print(doc);
}

parse()を実行すると、解析結果としてPDFDocumentを取得できます。

ByteStreamとは?

ByteStreamは、バイト列からPDFを読み込むためのRandomAccessStream実装です。

PDFファイルをFileから読み込み、その内容をバイト列として渡すことができます。

Dart

final bytes = File('sample.pdf').readAsBytesSync();

final stream = ByteStream(bytes);

作成したByteStreamPDFParserに渡します。

Dart

final doc = await PDFParser(stream).parse();

PDFファイルをすでにUint8Listなどのバイトデータとして保持している場合にも利用できます。

PDFParserとは?

PDFParserは、RandomAccessStreamからPDFドキュメントを解析するためのクラスです。

Dart

final parser = PDFParser(stream);

作成したParserに対してparse()を実行します。

Dart

final doc = await parser.parse();

この結果として取得できるのがPDFDocumentです。

PDFDocumentとは?

PDFDocumentは、解析されたPDFドキュメントを保持するクラスです。

Dart

final doc = await PDFParser(stream).parse();

PDFDocumentからは、PDFのCatalogを取得できます。

Dart

final catalog = await doc.catalog;

Catalogを起点として、PDFのページやアウトラインなどを取得できます。

PDFDocumentCatalogを取得する

PDFのCatalogは、ドキュメント全体の構造を表すオブジェクトです。

Dart

final catalog = await doc.catalog;

Catalogからページ情報を取得できます。

Dart

final pages = await catalog.getPages();

アウトラインも取得できます。

Dart

final outlines = await catalog.getOutlines();

PDFのページを取得する

ページ情報はgetPages()から取得できます。

Dart

final pages = await catalog.getPages();

特定のページを取得する場合は、getPageAtIndex()を利用します。

Dart

final firstPage = pages.getPageAtIndex(0);

インデックスは0から始まるため、0を指定すると最初のページを取得できます。

PDFPageObjectNode

取得した個々のページはPDFPageObjectNodeとして扱われます。

Dart

final page = pages.getPageAtIndex(0);

PDFPageObjectNodeには、ページに関するさまざまな情報が用意されています。

例えば、

  • mediaBox
  • cropBox
  • bleedBox
  • trimBox
  • artBox
  • rotate
  • resources
  • contentStreams
  • parent

などがあります。

ページサイズを取得する

mediaBoxからページのMedia Boxを取得できます。

Dart

final page = pages.getPageAtIndex(0);

final mediaBox = page.mediaBox;

print(mediaBox);

また、Crop Boxも取得できます。

Dart

final cropBox = page.cropBox;

print(cropBox);

PDFのページサイズや表示領域などを確認したい場合に利用できます。

contentStreamsを取得する

PDFページには、ページ上のコンテンツを表すストリームが含まれる場合があります。

contentStreamsから取得できます。

Dart

final page = pages.getPageAtIndex(0);

final streams = await page.contentStreams;

print(streams);

contentStreamsは複数のPDFStreamObjectを扱えるようになっています。

なお、以前のcontentStreamプロパティは非推奨となっており、現在はcontentStreamsの利用が推奨されています。

PDFのアウトラインを取得する

PDFのしおりや目次などのアウトラインを取得する場合は、CatalogのgetOutlines()を利用します。

Dart

final outlines = await catalog.getOutlines();

print(outlines);

アウトライン関連では、

  • PDFOutlineItem
  • PDFOutlineAction
  • PDFOutlineGoToAction
  • PDFOutlineActionType

などのクラスが用意されています。

PDFに含まれるしおりやナビゲーション情報を扱いたい場合に利用できます。

PDF内部のオブジェクト

dart_pdf_readerでは、PDF内部のさまざまなオブジェクトをDartのクラスとして扱えます。

代表的なものには以下があります。

クラス内容
PDFArrayPDFの配列
PDFBoolean真偽値
PDFDictionaryPDFの辞書
PDFHexString16進文字列
PDFIndirectObject間接オブジェクト
PDFLiteralStringリテラル文字列
PDFNamePDF Name
PDFNullNullオブジェクト
PDFNumber数値
PDFObjectReferenceオブジェクト参照
PDFStreamObjectPDFストリーム

このため、ページ情報だけではなく、PDFの内部構造をより細かく扱うことができます。

PDFArray

PDFArrayはPDFの配列を表すクラスです。

複数のPDFObjectを保持し、DartのIterableListMixinとしても利用できます。

例えば、要素数を取得できます。

Dart

PDFArray array = ...;

print(array.length);

インデックスを指定して要素を取得することもできます。

Dart

final item = array[0];

print(item);

PDFNumber

PDFNumberはPDF内部の数値を表します。

Dart

final number = PDFNumber(100);

整数として取得する場合はtoInt()を利用できます。

Dart

final value = number.toInt();

print(value);

小数として扱う場合はtoDouble()を利用できます。

Dart

final value = number.toDouble();

print(value);

PDFStreamObject

PDFのストリームデータはPDFStreamObjectとして扱われます。

ストリームはデータを最初からすべて読み込むのではなく、必要になったタイミングでreadRaw()を利用して読み取る仕組みになっています。

Dart

final data = await stream.readRaw();

print(data);

大量のストリームデータを扱うPDFを解析する場合にも、この仕組みを理解しておくとよいでしょう。

BufferedRandomAccessStream

BufferedRandomAccessStreamは、別のRandomAccessStreamから読み込んだデータをバッファリングするための実装です。

APIドキュメントでは、遅いストリームから読み込む場合のパフォーマンス改善に利用できるとされています。

Dart

final stream = BufferedRandomAccessStream(
  anotherStream,
);

ファイルから読み込む場合など、必要に応じて利用できます。

FileStreamを利用する

ファイルを直接読み込む場合はFileStreamを利用できます。

FileStreamdart_pdf_reader_ioライブラリから提供されています。

Dart

import 'dart:io';

import 'package:dart_pdf_reader/dart_pdf_reader.dart';
import 'package:dart_pdf_reader/dart_pdf_reader_io.dart';

Future<void> main() async {
  final file = await File('sample.pdf').open();

  final stream = FileStream(file);

  final doc = await PDFParser(stream).parse();

  print(doc);
}

ただし、現在のFileStreamはスマートなバッファリングを行わず、遅くなる可能性があるとされています。

そのため、必要に応じてBufferedRandomAccessStreamと組み合わせます。

Dart

import 'dart:io';

import 'package:dart_pdf_reader/dart_pdf_reader.dart';
import 'package:dart_pdf_reader/dart_pdf_reader_io.dart';

Future<void> main() async {
  final file = await File('sample.pdf').open();

  final stream = BufferedRandomAccessStream(
    FileStream(file),
  );

  final doc = await PDFParser(stream).parse();

  print(doc);
}

ページツリーを辿る

PDFPageObjectNodeには親ページノードを表すparentがあります。

これを利用してページツリーを親方向へ辿ることができます。

Dart

PDFPageNode? node = firstPage;

while (node != null) {
  print(await node.resources);

  node = node.parent;
}

PDFのページ構造を詳しく調べたい場合に利用できます。

ページのリソースを取得する

ページには画像やフォントなど、ページから参照されるリソースが存在します。

resourcesからページのリソースを取得できます。

Dart

final resources = await page.resources;

print(resources);

PDFの内部構造を解析する場合に利用できます。

PDF解析時の例外

dart_pdf_readerにはPDF解析時に利用される例外も用意されています。

代表的なものとして、

  • EOFException
  • ParseException
  • ActionTypeNotSupported

があります。

例えば解析処理をtry-catchで囲むことができます。

Dart

try {
  final doc = await PDFParser(stream).parse();

  print(doc);
} on ParseException catch (e) {
  print('PDFの解析に失敗しました: $e');
} on EOFException catch (e) {
  print('PDFの読み込みが途中で終了しました: $e');
}

外部からPDFを受け取るアプリケーションでは、壊れたPDFや想定外のPDFが入力される可能性も考慮しておくとよいでしょう。

Webにも対応

dart_pdf_readerはWebにも対応しています。

現在の対応プラットフォームは、

  • Android
  • iOS
  • Linux
  • macOS
  • Web
  • Windows

です。

そのため、Flutterアプリだけでなく、Flutter WebなどでPDF解析を行う用途にも利用できます。

PDFビューアーではない

dart_pdf_readerを利用する際に注意したいのが、PDFを画面に表示するためのビューアーではないという点です。

例えば、

PDFファイル
    ↓
dart_pdf_reader
    ↓
PDFの構造を解析

という用途が中心です。

一方、

PDFファイル
    ↓
Flutter Widgetとして表示

という目的の場合は、PDF表示に対応した別のパッケージを利用する必要があります。

PDF解析ツールに利用する

dart_pdf_readerは、PDFファイルの構造を解析するツールなどに利用できます。

例えば、

  • PDFの構造を調査するCLI
  • PDFのページ情報を取得するツール
  • PDFのアウトラインを解析するツール
  • PDFの内部オブジェクトを解析するツール
  • PDF処理のバックエンド

などです。

特にPDFを単純に表示するのではなく、PDFの構造そのものを扱いたい場合に適しています。

画像やテキストの抽出について

dart_pdf_readerはPDFの構造を読み取るためのライブラリですが、PDFから文章や画像を一般的な文書解析ライブラリのように簡単に抽出することを主目的とした高レベルAPIではありません。

パッケージ自体も、PDFデータについて多くの解釈を行わず、PDFからデータを読み取るための仕組みを提供するという位置付けです。

そのため、

  • PDFの文章を抽出したい
  • PDF内の画像を抽出したい
  • PDFをHTMLに変換したい

といった処理では、dart_pdf_readerだけで完結するとは限りません。

用途に応じて追加の解析処理が必要になります。

バージョン2.0.0での変更

2.0.0では、いくつか大きな変更が行われています。

主な変更は以下の通りです。

  • Webサポートの追加
  • 19バイトしかない不正なxrefセクションを持つPDFへの対応
  • FileStreamdart_pdf_reader_ioライブラリへ移動

特にFileStreamの移動は、古いバージョンからアップデートする場合に注意が必要です。

バージョン2.1.0での変更

2.1.0では、数値の比較にdeltaを使用する変更が行われました。

この変更はChangelog上でPotentially Breakingとされています。

古いバージョンからアップデートする場合は、既存コードへの影響を確認しておくとよいでしょう。

バージョン2.2.0での変更

現在の2.2.0では、依存パッケージの更新が行われています。

また、2.2.0の最小Dart SDKは3.0です。

ライセンス

dart_pdf_readerApache License 2.0で公開されています。

利用する際は、プロジェクトのライセンス条件も確認しておきましょう。

メリット

Pure DartでPDFを解析できる

PDF解析処理をDartコードから扱えるため、PDFの構造を扱う処理をDartで実装できます。

PDFの内部構造を扱える

ページだけではなく、

  • PDFオブジェクト
  • ページツリー
  • アウトライン
  • コンテンツストリーム
  • ページリソース

などを扱えます。

複数のプラットフォームに対応

Android、iOS、Linux、macOS、Web、Windowsに対応しています。

バイト列からPDFを読み込める

ByteStreamを利用することで、PDFファイルをバイト列として読み込んで解析できます。

Webに対応している

Webにも対応しているため、Flutter WebなどでPDF解析を行う用途にも利用できます。

注意点

PDFビューアーではない

PDFをFlutterの画面に表示することを目的としたパッケージではありません。

高レベルなPDF解析ライブラリではない

PDFの構造を読み取るための低レベル寄りのライブラリなので、「PDFから文章を抽出する」といった処理を簡単に実現するためのライブラリとは目的が異なります。

FileStreamのパフォーマンスに注意

FileStreamはスマートなバッファリングを行わず、遅くなる可能性があります。

必要に応じてBufferedRandomAccessStreamと組み合わせることを検討しましょう。

バージョンアップ時は変更点を確認する

2.0.0ではFileStreamの移動、2.1.0ではPotentially Breakingな変更が行われています。

古いバージョンからアップデートする場合は、変更内容を確認してから更新するのがおすすめです。

まとめ

dart_pdf_readerは、DartからPDFファイルの内部構造を読み取りたい場合に利用できるPure Dartライブラリです。

基本的な使い方は、

Dart

final stream = ByteStream(
  File('sample.pdf').readAsBytesSync(),
);

final doc = await PDFParser(stream).parse();

final catalog = await doc.catalog;
final pages = await catalog.getPages();
final outlines = await catalog.getOutlines();

final firstPage = pages.getPageAtIndex(0);

という流れになります。

主な機能として、

  • PDFファイルの解析
  • RandomAccessStream
  • ByteStream
  • FileStream
  • BufferedRandomAccessStream
  • PDFParser
  • PDFDocument
  • PDFページの取得
  • PDFページのリソース取得
  • アウトラインの取得
  • コンテンツストリームの取得
  • PDFオブジェクトの解析
  • Web対応
  • Android・iOS・Windows・macOS・Linux対応

などがあります。

特に、PDFを表示するのではなく、PDFそのものを解析・処理したい場合に適したパッケージです。

PDFのページ構造やオブジェクト、アウトライン、コンテンツストリームなどをDartから扱いたい場合は、dart_pdf_readerを候補として検討できます。

タイトルとURLをコピーしました