TOOLPIPO LAB PDF · 19条件

PDFのフォント埋め込みあり・なしは、どう違う?

未埋め込みのHelvetica、実TTF埋め込み、subset、Type3などの自作PDFを解析し、画面に表示できることとPDF自身にフォントがあることの違いを確認しました。

結論

PDFで文字が正常に見えていても、フォントファイルがPDFに埋め込まれているとは限りません。同じToolで比較すると、未埋め込みのStandard14フォントと、実TTFを埋め込んだPDFは異なる状態になりました。

subsetは異常ではなく、Type3も通常のTrueType等とは別の仕組みです。未埋め込みなら必ず文字化けする、埋め込みありなら全環境で同じ、と判断する検査ではありません。

今回比較したPDF

入力
既存の自作19 fixture+公開サンプル。本文は主要10条件を比較。実在資料・個人情報なし。
使用Tool
PDFフォント埋め込み・使用状況チェッカー。PDF.js 6.3.289。
実測
現行mainで全19件を再測定。代表6件は操作画面とも一致。Tool入力の外部送信0。
再現データ
19 PDF・README・実測JSON・ライセンス。公開サンプルはmixedと同一ハッシュです。

文字が見える=フォントが埋め込まれている、ではない

未埋め込みHelveticaのPDFにはテキストとフォント名があり、FontFileはありません。それでも、同じPDF.jsを使ったローカルChromiumの補助表示実験では「NON_EMBEDDED Helvetica」を画面に表示できました。

この表示実験は表示側のフォント利用を許可したCanvas処理です。埋め込みを調べるToolの解析設定とは分けています。別PC・Acrobat・プリンターとの見た目比較や、全環境での表示保証はしていません。

未埋め込みPDFはフォント名のみ、埋め込みPDFにはFontFile2がある
図1:自作PDFの構造差。表示できるかだけでは、PDF原本のFontFileの有無は分かりません。

未埋め込みHelveticaと、実TTF埋め込みを確認

a-standard14.pdfは使用フォント1件、埋め込みなし候補1件。Helveticaを1ページで使用していました。独立したPDF構造の確認でもFontFileなしです。

b-embedded.pdfは使用フォント1件、埋め込みあり1件。名前はToolPipoFixtureSans-Regular、種類はTrueType、使用ページは1です。実際に有効なTrueTypeをFontFile2へ格納したfixtureを使っています。これは全glyphの完全性や印刷品質の保証とは別です。

subsetは異常ではない

c-subset.pdfは埋め込みあり1件でした。raw nameはAAAAAA+ToolPipoFixtureSans-Regular、表示名はToolPipoFixtureSans-Regular、subset tagはAAAAAA+です。

subsetは、PDFで使うglyph(文字の形)だけを含める方式として使われます。このToolは6文字の大文字英字+「+」という名前形式からsubset候補を表示します。全glyph収録内容を比較してsubsetを証明したり、必要なglyphが全て揃うと判定したりしていません。

必要なglyphを選ぶ概念とAAAAAA+という名前形式
図2:subsetの概念図。A・C・F・Hは説明用の例で、今回のfixtureのglyph一覧ではありません。

Type3は別の仕組み

d-type3.pdfはType3 1件、通常の埋め込みあり・なしは0件でした。実際の結果表示は「Type3(PDF内のglyph定義)」です。

Type3はPDFの描画命令でglyphを定義できます。今回のfixtureは三角形を描くCharProcsを使っているため、通常のFontFile埋め込み判定とは分けます。Type3であることを危険扱いしません。

TrueTypeはfont program、Type3はPDF内の描画命令からglyphを作る
図3:glyphを定義する仕組みの概念比較。形式だけで出力品質は判定できません。

1つのPDFに埋め込みあり・なしが混在することもある

e-mixed.pdfは使用フォント2件、埋め込みあり1件、埋め込みなし候補1件でした。TrueTypeとHelveticaはどちらも1ページで使用しています。1つのPDFだから、フォント状態も1種類とは限りません。

使用ページを確認すると、PDF内の使い分けが分かる

f-page-fonts.pdfでは、埋め込みTrueTypeは1ページ、未埋め込みHelveticaは2ページでした。g-repeated.pdfの同一TrueTypeは1–3, 5–7ページに集計され、4ページのHelveticaと分かれました。同じフォントオブジェクトをページごとに別件へ増やしてはいません。

同じフォント名でも、別resourceの場合がある

duplicate-resource.pdfは同じraw nameのTrueTypeを使いますが、内部のフォントオブジェクトは別です。結果は埋め込みあり2件で、「同名のfont resourceが2件」と表示されました。

名前が同じ=PDF内部でも同じ1個のresourceとは限りません。Toolは人が読む名前だけでまとめず、内部IDを使って使用ページを集計します。

画像だけのPDFでは使用フォント0件

h-image-only.pdfは使用フォント0件で正常完了しました。今回のfixtureは色見本の画像XObjectで、文字画像をOCRした実験ではありません。

スキャンPDFなどで文字の見た目が画像として保存されている場合も、テキスト用のフォントを使用していないことがあります。画像に見える文字や書体を調べることは別の処理です。このToolはOCRしません。

テキストのFont resourceと、画像だけで使用フォント0件になる違い
図4:文字をテキストとして持つ場合と、画像の見た目として持つ場合の概念比較。実測fixtureは色画像です。

未使用resourceは、初版の一覧対象ではない

unused-resource.pdfは、resource辞書に埋め込みTrueTypeと未使用Helveticaを定義しています。実際のtext描画はTrueTypeだけなので、結果は使用フォント1件、埋め込みあり1件でした。

初版は「実際にページのtext contentで使われているfont」を対象としており、未使用resourceは一覧に含めません。PDF内部に定義された全resourceを完全列挙する検査ではありません。

主要10条件で分かったことと、分からないこと

条件Tool判定分かったこと分からないこと
未埋め込みHelvetica埋め込みなし候補FontFileなしを構造でも確認別PCでの実際の表示
実TTF埋め込み埋め込みあり利用可能なfont dataを確認全glyphの完全性
subset埋め込み埋め込みあり+subset名AAAAAA+という名前形式必要glyphが全て揃うか
Type3Type3glyphをPDF描画命令で定義出力品質全体
埋め込み+未埋め込み混在埋め込みあり/埋め込みなし候補1つのPDFに2状態表示・印刷の保証
ページ別フォント埋め込みあり/埋め込みなし候補使用ページ1と2を識別全ページの見た目
同じフォントを複数ページ埋め込みあり/埋め込みなし候補1–3, 5–7に集計glyphの健全性
同名・別resource埋め込みあり/埋め込みあり同名でも2件として集計同じ描画結果か
画像だけ使用フォント0件使用フォント0件で正常完了画像内の文字・OCR
未使用resource埋め込みあり未使用Helveticaは対象外未使用resourceの完全列挙

Standard14全14種と、Arialも確認

all-standard14.pdfの全14種は埋め込みあり0件、埋め込みなし候補14件でした。以下は埋め込み解析の結果です。14種全ての表示品質を別環境で検証したという意味ではありません。

Standard14全14種の実測結果を見る
FontTool判定
Helvetica埋め込みなし候補
Helvetica-Bold埋め込みなし候補
Helvetica-Oblique埋め込みなし候補
Helvetica-BoldOblique埋め込みなし候補
Times-Roman埋め込みなし候補
Times-Bold埋め込みなし候補
Times-Italic埋め込みなし候補
Times-BoldItalic埋め込みなし候補
Courier埋め込みなし候補
Courier-Bold埋め込みなし候補
Courier-Oblique埋め込みなし候補
Courier-BoldOblique埋め込みなし候補
Symbol埋め込みなし候補
ZapfDingbats埋め込みなし候補

Standard14以外のsystem-arial.pdfもArial、埋め込みなし候補1件でした。Standard14だけを名前で特別扱いする結果ではありません。解析ではOSのフォントを使わない設定です。

開発時に確認した全fixture

現行mainで19件を再測定しました。保護・破損・501ページは意図した拒否結果です。ページ数はPDF構造から別途取得し、Toolの解析成功と区別しています。

19 fixtureの期待値と実測値を見る
fixture名ページ数期待する状態実際の状態備考
a-standard14.pdf1埋め込み0/候補1/Type3 0使用1件/埋め込み0/未埋め込み候補1/Type3 0/判定不能0FontFileなしのHelvetica
b-embedded.pdf1埋め込み1/候補0/Type3 0使用1件/埋め込み1/未埋め込み候補0/Type3 0/判定不能0有効なTrueType FontFile2
c-subset.pdf1埋め込み1/候補0/Type3 0使用1件/埋め込み1/未埋め込み候補0/Type3 0/判定不能0AAAAAA+のsubset名
d-type3.pdf1埋め込み0/候補0/Type3 1使用1件/埋め込み0/未埋め込み候補0/Type3 1/判定不能0実際のCharProcs描画命令
e-mixed.pdf1埋め込み1/候補1/Type3 0使用2件/埋め込み1/未埋め込み候補1/Type3 0/判定不能0埋め込みと未埋め込みの混在
f-page-fonts.pdf2埋め込み1/候補1/Type3 0使用2件/埋め込み1/未埋め込み候補1/Type3 0/判定不能0ページ1と2で使用フォントが異なる
g-repeated.pdf7埋め込み1/候補1/Type3 0使用2件/埋め込み1/未埋め込み候補1/Type3 0/判定不能0同一フォントを1–3, 5–7ページで使用
h-image-only.pdf1埋め込み0/候補0/Type3 0使用0件/埋め込み0/未埋め込み候補0/Type3 0/判定不能0色見本の画像XObject。文字画像やOCRの検証ではない
duplicate-resource.pdf1埋め込み2/候補0/Type3 0使用2件/埋め込み2/未埋め込み候補0/Type3 0/判定不能0同名の独立したフォントオブジェクト2件
unused-resource.pdf1埋め込み1/候補0/Type3 0使用1件/埋め込み1/未埋め込み候補0/Type3 0/判定不能0未使用Helvetica resourceは対象外
all-standard14.pdf1埋め込み0/候補14/Type3 0使用14件/埋め込み0/未埋め込み候補14/Type3 0/判定不能0Standard14全14種。表示品質の一括検証ではない
system-arial.pdf1埋め込み0/候補1/Type3 0使用1件/埋め込み0/未埋め込み候補1/Type3 0/判定不能0Arial。OSフォントを解析に使わない
long-name.pdf1埋め込み1/候補0/Type3 0使用1件/埋め込み1/未埋め込み候補0/Type3 0/判定不能0長いPDF内部フォント名
pages-20.pdf20埋め込み1/候補0/Type3 0使用1件/埋め込み1/未埋め込み候補0/Type3 0/判定不能0同じフォントを20ページ
pages-100.pdf100埋め込み1/候補0/Type3 0使用1件/埋め込み1/未埋め込み候補0/Type3 0/判定不能0同じフォントを100ページ
pages-501.pdf501500ページまでのPDFに対応しています。500ページまでのPDFに対応しています。上限超過で拒否
password.pdf1パスワード付きPDFには対応していません。パスワード付きPDFには対応していません。保護PDF。パスワードfixture-password
malformed.pdf取得不能PDFを解析できませんでした。破損または対応外のPDFの可能性があります。PDFを解析できませんでした。破損または対応外のPDFの可能性があります。意図した破損PDF
security.pdf1埋め込み1/候補1/Type3 0使用2件/埋め込み1/未埋め込み候補1/Type3 0/判定不能0JavaScript・URI・添付を含む。開かず検査する
使用ページ・raw name・内部IDの詳細を見る
fixtureフォント名状態使用ページ内部ID
a-standard14.pdfHelvetica埋め込みなし候補1g_d0_f1
b-embedded.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d1_f1
c-subset.pdfAAAAAA+ToolPipoFixtureSans-Regular埋め込みあり1g_d2_f2
d-type3.pdfType3Type31g_d3_f1
e-mixed.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d4_f1
e-mixed.pdfHelvetica埋め込みなし候補1g_d4_f2
f-page-fonts.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d5_f1
f-page-fonts.pdfHelvetica埋め込みなし候補2g_d5_f2
g-repeated.pdfToolPipoFixtureSans-Regular埋め込みあり1–3, 5–7g_d6_f1
g-repeated.pdfHelvetica埋め込みなし候補4g_d6_f2
duplicate-resource.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d8_f1
duplicate-resource.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d8_f2
unused-resource.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d9_f1
all-standard14.pdfHelvetica埋め込みなし候補1g_d10_f1
all-standard14.pdfHelvetica-Bold埋め込みなし候補1g_d10_f2
all-standard14.pdfHelvetica-Oblique埋め込みなし候補1g_d10_f3
all-standard14.pdfHelvetica-BoldOblique埋め込みなし候補1g_d10_f4
all-standard14.pdfTimes-Roman埋め込みなし候補1g_d10_f5
all-standard14.pdfTimes-Bold埋め込みなし候補1g_d10_f6
all-standard14.pdfTimes-Italic埋め込みなし候補1g_d10_f7
all-standard14.pdfTimes-BoldItalic埋め込みなし候補1g_d10_f8
all-standard14.pdfCourier埋め込みなし候補1g_d10_f9
all-standard14.pdfCourier-Bold埋め込みなし候補1g_d10_f10
all-standard14.pdfCourier-Oblique埋め込みなし候補1g_d10_f11
all-standard14.pdfCourier-BoldOblique埋め込みなし候補1g_d10_f12
all-standard14.pdfSymbol埋め込みなし候補1g_d10_f13
all-standard14.pdfZapfDingbats埋め込みなし候補1g_d10_f14
system-arial.pdfArial埋め込みなし候補1g_d11_f1
long-name.pdfToolPipoLongFontNameVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLongVeryLong埋め込みあり1g_d12_f1
pages-20.pdfToolPipoFixtureSans-Regular埋め込みあり1–20g_d13_f1
pages-100.pdfToolPipoFixtureSans-Regular埋め込みあり1–100g_d14_f1
security.pdfToolPipoFixtureSans-Regular埋め込みあり1g_d18_f1
security.pdfHelvetica埋め込みなし候補1g_d18_f2

内部IDはPDF.jsの読込順などで変わる場合があり、ファイルをまたぐ同一性の証明には使えません。

「埋め込みなし候補」と表示する理由

表示は「埋め込みなし候補・代替フォントに依存する可能性」です。利用可能なfont fileを確認できない理由には、元からない場合のほか、破損フォント、対応外構造、parser上の取得不能もあり得ます。

未埋め込みは、表示環境によって代替フォントが使われる可能性を考える材料の1つです。文字化けやレイアウト崩れをこの検査だけで予測することはできません。

このToolで分からないこと

  • 別PC・Adobe Acrobatの最終表示、プリンターの出力結果
  • glyphの完全性、ToUnicodeの正しさ、フォントデータ破損の完全検査
  • フォントライセンス、埋め込み権限、商用利用条件、PDF/A適合
  • 未使用resourceの完全列挙、OCR画像内のフォント

埋め込みありは、埋め込み権限ありという意味ではありません。

自分のPDFの使用フォントを確認する

PDFを入れると、使用フォント・状態・subset名・使用ページをブラウザ内で確認できます。本文・フォントバイナリの外部送信や抽出保存はしません。

自分のPDFの使用フォントを確認する

再現ファイルと実測JSON

19条件のPDFと実測結果をダウンロード/公開results JSON/fixtureフォントのライセンス

全て自作の合成資料です。font binary単体は配布せず、ライセンスに従ってPDFへ埋め込まれたものだけを含めます。security.pdfには検証用JavaScript・URI・添付があります。実行・展開せずToolで検査してください。保護PDFの検証パスワードはREADMEに記載しています。

package:500,207 bytes

SHA-256:c6324f76081c392cbb0d9ee95b8b05bf04f25ed8d87d3ffbc569fb7576361f6c

循環参照を避け、ZIP自身の最終ハッシュは外部の公開JSONを正本とします。同梱JSONは同じ測定値のsnapshotです。

検証条件・実装資料

測定時のToolはcommit 525eb505b602779cc58fdb07367f97875715b1ba、PDF.js 6.3.289です。ページごとに描画命令を読み、text itemのfontNameとcommonObjsを対応させます。

fontExtraProperties: true、disableFontFace: true、useSystemFonts: false、useWorkerFetch: false、enableXfa: false、isEvalSupported: false。Standard14用の内部font data URLは指定しません。表示のための代替フォントを「PDF自身の埋め込みフォント」と誤認しないためです。

font objectの実測値とclassifierを見る
fixturefont名missingFiledataありType3typesystemFontInfo
a-standard14.pdfHelveticatruefalsefalseType1false
b-embedded.pdfToolPipoFixtureSans-RegularfalsetruefalseTrueTypefalse
c-subset.pdfAAAAAA+ToolPipoFixtureSans-RegularfalsetruefalseTrueTypefalse
d-type3.pdfType3falsefalsetrueType3false
  1. font objectを取得できない・error・invalid PDF.js font・system font情報ありは「判定不能」。
  2. isType3Font === trueはType3。通常分類と分けます。
  3. 必要なType3フラグ・missingFile・type情報が不足する場合は「判定不能」。
  4. missingFile === trueかつ利用可能なUint8Arrayデータなしは「埋め込みなし候補」。dataもある矛盾した状態は「判定不能」。
  5. missingFile === falseかつ利用可能なUint8Arrayデータありは、固定設定の実fixture検証に基づき「埋め込みあり」。dataなしは「判定不能」。

font.data単独では判定していません。PDF.jsの内部Standard14 fontやsystem substitutionを原本のfont streamと混同しない条件で照合します。data.lengthは変換後データの可能性があるため、原本に埋め込まれた容量として表示しません。