本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:PDFからテキスト・座標・フォント情報を抽出できる「pdftools」パッケージの紹介

研究や実務では、PDF形式で配布された資料からテキストや数値を取り出し、集計や分析に使いたい場面があります。しかし、PDFは表示のためのレイアウト情報を持つ形式であり、そこから必要な文字情報だけを取り出すには手間がかかります。

「pdftools」パッケージは、Popplerライブラリを基盤として、PDFからページ単位のテキストや単語ごとの座標、埋め込みフォント、文書のメタデータを取り出すことが可能です。また、各ページを指定した解像度でビットマップ画像に描画したり、PNGやJPEGなどの画像ファイルへ変換したりすることも可能です。本パッケージの利用で、PDF資料を起点としたデータの抽出や画像化を、R上で一貫して進められるのではないかと考えます。

パッケージバージョンは3.9.1。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("pdftools")

# パッケージの読み込み
library("pdftools")
Using poppler version 26.01.0
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

pdftoolsの関数は、大きくテキスト抽出系とレンダリング系に分けられます。テキスト抽出系のpdf_textはページ単位の文字列を、pdf_dataは単語ごとに位置と大きさを持つデータフレームを返します。pdf_infoは作成日やページ数などのメタデータ、pdf_fontsは埋め込みフォント、pdf_pagesizeは各ページの寸法を返します。レンダリング系のpdf_render_pageはページをビットマップとしてメモリ上に描画し、pdf_convertはページを画像ファイルとして書き出します。

以下では、京都府の宇治茶の産地別生産量をまとめた擬似データを、日本語を含む2ページのPDFとして書き出し、そのPDFを題材に各関数の動作を確認します。

# 作業用の一時ファイルとして出力するPDFのパス
ocha_pdf <- file.path(tempdir(), "uji_ocha_report.pdf")

# 京都府の宇治茶産地に関する擬似データ
sanchi <- data.frame(
  産地 = c("宇治市", "和束町", "宇治田原町", "南山城村", "京田辺市"),
  荒茶生産量 = c(418, 605, 352, 274, 191),
  主力品種 = c("やぶきた", "ごこう", "さみどり", "おくみどり", "うじひかり")
)

# 1ページ目に産地一覧、2ページ目に棒グラフを描いたPDFを書き出す
cairo_pdf(ocha_pdf, width = 7, height = 5, onefile = TRUE)
plot.new()
title(main = "宇治茶 産地別生産量レポート(擬似データ)")

# 産地ごとの生産量と主力品種を1行ずつ書き込む
text(0, seq(0.9, 0.5, length.out = nrow(sanchi)),
  adj = 0,
  labels = paste0(sanchi$産地, ":", sanchi$荒茶生産量, "トン(", sanchi$主力品種, ")")
)

# 2ページ目として棒グラフを描く
barplot(sanchi$荒茶生産量,
  names.arg = sanchi$産地,
  main = "産地別の荒茶生産量", ylab = "トン"
)
dev.off()
png
  2

PDFのメタデータを取得する:pdf_infoコマンド

作成日時、更新日時、ページ数、PDFのバージョン、作成に使われたソフト名などの文書情報をリストとして返します。ページ数だけを使いたい場合は結果のpages要素を参照します。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
# PDFのメタデータ(作成日・ページ数・作成ソフトなど)を取得する
joho <- pdf_info(ocha_pdf)

# ページ数だけを取り出す
joho$pages
[1] 2

# 文書全体の情報を表示する
joho
$version
[1] "1.7"

$pages
[1] 2

$encrypted
[1] FALSE

$linearized
[1] FALSE

$keys
$keys$Producer
[1] "cairo 1.18.4 (https://cairographics.org)"

$created
[1] "2026-09-04 12:24:57 JST"

$modified
[1] "1970-01-01 08:59:59 JST"

$metadata
[1] ""

$locked
[1] FALSE

$attachments
### 出力は省略(残り4行)

ページ単位でテキストを抽出する:pdf_textコマンド

各ページのテキストを1要素とする文字列ベクトルを返します。既定では紙面のレイアウト順に並べ替えて返し、raw = TRUEを指定するとPDF内部のストリーム順のまま取り出します。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
raw物理的なレイアウト順ではなくrawストリーム順でテキストを返すFALSE
# ページごとの文字列ベクトルとしてテキストを抽出する
honbun <- pdf_text(ocha_pdf)

# 1ページ目のテキストを表示する
cat(honbun[1])
         宇治茶 産地別生産量レポート(擬似データ)

宇治市:418トン(やぶきた)
和束町:605トン(ごこう)
宇治田原町:352トン(さみどり)
南山城村:274トン(おくみどり)
京田辺市:191トン(うじひかり)

# 内部のストリーム順のまま取り出す
honbun_raw <- pdf_text(ocha_pdf, raw = TRUE)

単語ごとの座標付きでテキストを取り出す:pdf_dataコマンド

ページごとに、単語とその位置(x、y)、幅、高さ、書字方向などを列に持つデータフレームのリストを返します。表のセルや見出しなど、紙面上の位置を手がかりに抽出したいときに使います。font_info = TRUEを指定すると各単語のフォント情報も付きますが、新しいPopplerが必要です。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
font_infoTRUEのとき各ボックスのフォント情報も抽出する(新しいPopplerが必要で、なければエラーになる)FALSE
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
# 単語ごとに位置・大きさを持つデータフレームのリストとして抽出する
moji <- pdf_data(ocha_pdf)

# 1ページ目の先頭部分を確認する
head(moji[[1]])
  width height   x   y space                               text
1    32     16 156  21  TRUE                             宇治茶
2   183     16 192  21 FALSE 産地別生産量レポート(擬似データ)
3   128     13  74  81 FALSE        宇治市:418トン(やぶきた)
4   119     13  74 102 FALSE          和束町:605トン(ごこう)
5   146     13  74 124 FALSE    宇治田原町:352トン(さみどり)
6   146     13  74 145 FALSE    南山城村:274トン(おくみどり)

# 各単語のフォント情報も付けて抽出する
moji_font <- pdf_data(ocha_pdf, font_info = TRUE)

埋め込みフォントを一覧する:pdf_fontsコマンド

PDFで使われているフォント名、種類、埋め込みの有無などをデータフレームで返します。フォントが埋め込まれていない場合、環境によって表示や抽出結果が変わることがあるため、その確認に使えます。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
# PDFに埋め込まれたフォントの一覧を取得する
font_ichiran <- pdf_fonts(ocha_pdf)

# フォント名と埋め込みの有無を表示する
font_ichiran
                 name         type embedded file
1 BICLDM+Arial-BoldMT cid_truetype     TRUE
2 KMJXUC+Arial-BoldMT     truetype     TRUE
3      HCWRAC+ArialMT cid_truetype     TRUE
4      RJAMDI+ArialMT     truetype     TRUE

ページの寸法を取得する:pdf_pagesizeコマンド

各ページの幅と高さをポイント単位(1ポイント=1/72インチ)でデータフレームとして返します。用紙サイズの確認や、pdf_dataで得た座標を割合に直すときの基準として使えます。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
# 各ページの幅・高さ(ポイント単位)を取得する
size <- pdf_pagesize(ocha_pdf)

# ページごとの寸法を表示する
size
  top right bottom left width height
1   0   504    360    0   504    360
2   0   504    360    0   504    360

ページをビットマップ画像に描画する:pdf_render_pageコマンド

指定したページを指定解像度で描画し、画像データをrawベクトル(またはnumeric = TRUEで0〜1の実数配列)としてメモリ上に返します。pngパッケージと組み合わせると、任意のページをPNGとして保存できます。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
page描画するページ番号1
dpi描画時の解像度(1インチあたりのドット数)72
numericraw出力を0〜1の実数値に変換するFALSE
antialiasアンチエイリアスを有効にする(”text”、”draw”、TRUE、FALSEのいずれか)TRUE
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
# 2ページ目を150dpiのビットマップとして描画する
bitmap <- pdf_render_page(ocha_pdf, page = 2, dpi = 150)

# 画像の次元(チャンネル数・幅・高さ)を確認する
dim(bitmap)
[1]    4 1050  750

# pngパッケージでPNGファイルとして保存する
png::writePNG(bitmap, file.path(tempdir(), "ocha_page2.png"))

ページを画像ファイルに変換する:pdf_convertコマンド

指定したページをPNGやJPEGなどの画像ファイルとして書き出し、生成したファイルのパスを返します。pagesで対象ページを、filenamesで出力先を指定します。利用できる形式はpoppler_config()$supported_image_formatsで確認できます。

オプション意味初期値
pdfPDFファイルのパス、またはPDFデータのrawベクトルなし
format出力形式を表す文字列(”png”や”jpeg”など。poppler_config()$supported_image_formatsのいずれかと一致する必要がある)“png”
pages描画するページ番号のベクトル(1始まり)。NULLは全ページNULL
filenamespagesと同じ長さの出力ファイル名ベクトル。pagesとformatで展開される書式文字列でもよいNULL
dpi描画時の解像度(1インチあたりのドット数)72
antialiasアンチエイリアスを有効にする(”text”、”draw”、TRUE、FALSEのいずれか)TRUE
opwPDFを開くためのオーナーパスワード(文字列)“”
upwPDFを開くためのユーザーパスワード(文字列)“”
verbose進捗情報を標準出力に表示するTRUE
# 出力先の画像ファイル名を2ページ分用意する
shutsuryoku <- file.path(tempdir(), c("ocha_p1.png", "ocha_p2.png"))

# 1〜2ページ目をそれぞれPNG画像ファイルに変換する
gazou <- pdf_convert(ocha_pdf,
  format = "png", pages = 1:2,
  filenames = shutsuryoku, dpi = 150
)
Converting page 1 to C:\Users\chalu\AppData\Local\Temp\RtmpmsbcKz/ocha_p1.png... done!
Converting page 2 to C:\Users\chalu\AppData\Local\Temp\RtmpmsbcKz/ocha_p2.png... done!

# 生成された画像ファイルのパスを表示する
gazou
[1] "C:\\Users\\chalu\\AppData\\Local\\Temp\\RtmpmsbcKz/ocha_p1.png"
[2] "C:\\Users\\chalu\\AppData\\Local\\Temp\\RtmpmsbcKz/ocha_p2.png"


この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。