AIで作ったPDF商品を販売前に検査する|4ページになった初稿を3ページへ戻した

PDF を開くと、表紙も記入欄も整っていました。ところがページ数は 3 ではなく 4 です。途中に「使い方」が 2 回入り、プレビュー用の複製ページが残っていました。
2026 年 9 月 28 日、AI で下書きした業務棚卸しシートを、販売用 PDF へ変換する手順を試しました。目視だけではなく、ページ数、見出しの重複、フォント埋め込みをコマンドで検査します。最初の PDF は終了コード1で止まり、修正後は0になりました。
個人でデジタル商品を作る時は、生成できたことと、購入者へ渡せることを分ける必要があります。PDF が開けるだけでは、完成とは判定しません。
前回完了時から変えたこと
前回は、プロンプト商品の 12 ケースを検査し、必須項目の欠落を止めました。今回は中身を PDF へ変換した後の検査へ進みます。
| 時点 | 完了条件 | 見落とす問題 |
|---|---|---|
| 前回完了時 | 商品データが受け入れ条件を通ります | PDF変換後の重複やフォント状態は見ません |
| 今回完了後 | PDFのページ数、見出し、フォントを検査します | 内容の正確さと使いやすさは人が確認します |
読み飛ばせる章: ChromeでHTMLをPDFへ変換できる場合は、「PDFの中身を3項目で検査する」から進めます。
なぜ、完成した見た目だけでは足りないのか
AI は、表紙、説明、記入欄を短時間で作れます。HTML へ流し込み、ブラウザで印刷すれば PDF もできます。しかし、生成途中で複製したページや、印刷時の改ページは画面上で見落としやすい部分です。
今回の初稿には、プレビュー用に複製した「使い方」が残っていました。各ページの色や余白は崩れていません。3 ページを想定していた人だけが、4 ページ目の存在を問題だと判断できます。
そこで、完成条件を PDF の外側に置きます。
[AIで本文とHTMLを作る]
│
▼
[ChromeでPDFへ変換]
│
▼
[販売前検査]
├── 3ページか
├── 必須見出しが各1回か
└── 未埋め込みフォントが0か
│
┌────┴────┐
▼ ▼
PASS FAIL
│ └── HTMLを直して再変換
▼
[人が内容と操作性を確認]
検査コードは、PDF の価値を採点しません。機械で数えられる欠陥だけを、販売前に止めます。
用語をそろえる
| 用語 | この回での意味 |
|---|---|
| ヘッドレスChrome | 画面を開かず、コマンドからWebページを処理するChromeです |
pdfinfo | PDFのページ数や用紙サイズなどを表示するPopplerの道具です |
pdftotext | PDFの文字をプレーンテキストへ変換する道具です |
pdffonts | PDFで使うフォントと埋め込み状態を一覧にする道具です |
| フォント埋め込み | 表示に必要な字体をPDF内へ含める処理です |
| 終了コード | コマンドの成功を0、失敗を0以外で示す値です |
4ページの初稿を再現する
作業用ディレクトリで、次の HTML をoffer-before.htmlとして保存します。3 ページの商品を想定していますが、「使い方」の複製が 1 ページ残っています。
cat > offer-before.html <<'HTML'
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>AI業務棚卸しシート</title>
<style>
@page { size: A4; margin: 0; }
* { box-sizing: border-box; }
body { margin: 0; font-family: "Noto Sans CJK JP", sans-serif; }
.sheet { width: 210mm; height: 297mm; padding: 24mm 20mm; break-after: page; }
</style>
</head>
<body>
<section class="sheet"><h1>AI業務棚卸しシート</h1><p>事業の作業を整理します。</p></section>
<section class="sheet"><h2>使い方</h2><p>入力と完成条件を分けます。</p></section>
<section class="sheet"><h2>使い方</h2><p>複製ページが残っています。</p></section>
<section class="sheet"><h2>棚卸し欄</h2><p>作業名:</p><p>入力:</p><p>完成条件:</p></section>
</body>
</html>
HTML
この HTML を Chrome で PDF へ変換します。
google-chrome \
--headless \
--disable-gpu \
--no-pdf-header-footer \
--print-to-pdf=offer-before.pdf \
file://$PWD/offer-before.html
Chrome の標準エラーには、作成したファイル容量が表示されます。今回の実行後、pdfinfoでページ数を読むと次の結果になりました。
pdfinfo offer-before.pdf | grep '^Pages:'
Pages: 4
ここで期待値の 3 ページと食い違います。見た目を確認する前でも、初稿を販売候補から外せます。
PDFの中身を3項目で検査する
次に、検査スクリプトをpreflight-pdf.shとして保存します。読み出した文字は一時ファイルへ置き、見出しの回数を数えます。
cat > preflight-pdf.sh <<'SH'
#!/usr/bin/env bash
set -euo pipefail
pdf=${1:?usage: preflight-pdf.sh FILE.pdf}
expected_pages=3
pages=$(pdfinfo "$pdf" | awk '/^Pages:/ {print $2}')
pdftotext "$pdf" - | tr -d '\f' > /tmp/offer-extracted.txt
use_count=$(grep -c '^使い方$' /tmp/offer-extracted.txt || true)
stock_count=$(grep -c '^棚卸し欄$' /tmp/offer-extracted.txt || true)
nonembedded=$(pdffonts "$pdf" | awk 'NR>2 && $4=="no" {n++} END {print n+0}')
printf 'pages=%s expected=%s\n' "$pages" "$expected_pages"
printf 'heading_use=%s heading_sheet=%s\n' "$use_count" "$stock_count"
printf 'nonembedded_fonts=%s\n' "$nonembedded"
test "$pages" -eq "$expected_pages"
test "$use_count" -eq 1
test "$stock_count" -eq 1
test "$nonembedded" -eq 0
printf 'result=PASS\n'
SH
chmod +x preflight-pdf.sh
初稿を検査します。
./preflight-pdf.sh offer-before.pdf
printf 'exit=%s\n' "$?"
実測結果は次の通りです。set -eを呼び出し側で有効にしている場合、printfへ進まず終了します。
pages=4 expected=3
heading_use=2 heading_sheet=1
nonembedded_fonts=0
exit=1
ページ数だけでなく、「使い方」が 2 回あることも分かりました。未埋め込みフォントは 0 です。今回の失敗原因を、フォントではなく重複ページへ絞れます。
重複を消し、同じ物差しで測り直す
初稿を複製し、プレビュー用のページだけを削除します。最後のページには、不要な改ページを付けません。
python - <<'PY'
from pathlib import Path
src = Path("offer-before.html").read_text()
src = src.replace(
'.sheet { width: 210mm; height: 297mm; padding: 24mm 20mm; break-after: page; }',
'.sheet { width: 210mm; height: 297mm; padding: 24mm 20mm; break-after: page; }\n'
'.sheet:last-child { break-after: auto; }',
)
src = src.replace(
'<section class="sheet"><h2>使い方</h2><p>複製ページが残っています。</p></section>\n',
'',
)
Path("offer-after.html").write_text(src)
PY
google-chrome \
--headless \
--disable-gpu \
--no-pdf-header-footer \
--print-to-pdf=offer-after.pdf \
file://$PWD/offer-after.html
同じ検査スクリプトを使います。修正に合わせて期待値を変えると、改善したのか、判定を緩めたのか分からなくなります。
./preflight-pdf.sh offer-after.pdf
printf 'exit=%s\n' "$?"
修正後の実測結果です。
pages=3 expected=3
heading_use=1 heading_sheet=1
nonembedded_fonts=0
result=PASS
exit=0
3 ページになり、2 つの必須見出しは各 1 回です。フォント状態も初稿から悪化していません。
テキスト抽出は購入後の使いやすさにも関わる
pdftotextで文字を取り出せるかは、重複検査だけの問題ではありません。購入者が PDF 内を検索し、必要な箇所をコピーできるかにも関わります。
ただし、文字を抽出できればアクセシブルな PDF になるわけではありません。文書の言語、見出し構造、画像の代替情報、読み上げ順などは別に確認します。Adobe のアクセシビリティ検査も、機械検査だけでは確認できない項目があると案内しています。
フォントについても役割を分けます。pdffontsのemb列は、フォントが PDF へ埋め込まれているかを示します。埋め込みがyesでも、文字順や見出し構造の正しさまでは保証しません。
| 検査 | 分かること | 分からないこと |
|---|---|---|
pdfinfo | ページ数や用紙サイズです | ページ内容の正しさです |
pdftotext | 文字を抽出できるか、見出しが何回あるかです | 見た目と読み上げ順の品質です |
pdffonts | フォントの種類と埋め込み状態です | 文章の正確さと商品価値です |
| 人の確認 | 記入しやすさ、内容、販売条件です | 再実行時の機械的な回帰です |
よくあるエラー
| 症状 | 原因 | 対応 |
|---|---|---|
| 想定より1ページ多いです | 複製ページか末尾の改ページが残っています | pdfinfoで件数を止め、HTMLのsection数を確認します |
| 見出し件数が0です | 文字が画像化され、テキストとして残っていません | 画像ではなくHTMLの文字として配置し直します |
| 日本語が文字化けします | 使用フォントか文字コードに問題があります | UTF-8と日本語フォントを指定し、再抽出します |
nonembedded_fontsが1以上です | 端末側のフォントへ依存しています | ライセンスを確認したフォントを埋め込みます |
| 手元では通るのに別環境で崩れます | Chromeやフォントの版が違います | 変換環境を固定し、PDF自体を検査対象にします |
| 検査は通るのに使いにくいです | 件数検査を人の確認の代わりにしています | 印刷、検索、コピー、記入を実際に試します |
PASSは販売開始の合図ではない
今回の検査で確認できたのは、3 ページ、必須見出し各 1 回、未埋め込みフォント 0 の 3 点です。文章の正確さや、購入者が記入しやすいかは別に残ります。
AI でデジタル商品を作ると、初稿が早く出るため、完成判定も早めたくなります。しかし、見た目が整った 4 ページをそのまま渡すと、購入者が重複の意味を考えることになります。作り手の確認不足を、購入者へ移してはいけません。
私は、AI へ作成を任せる範囲が広いほど、最後の判定を単純なコマンドへ戻します。PDF を開いた感想ではなく、期待するページ数と見出し数を先に固定します。失敗時は商品を消さず、終了コード1と原因を残して直します。
次は、同じ PDF を画面、印刷、スマートフォンで確認し、記入欄の大きさを測ります。機械検査で欠落を止めた後に、人が使う場面へ進みます。
一次情報
| 資料 | 確認した内容 |
|---|---|
| Chrome for Developers: Headless command-line reference | --print-to-pdfと--no-pdf-header-footerの使い方 |
| Debian Manpages: pdfinfo | PDFのメタデータとページ情報を表示する仕様 |
| Debian Manpages: pdftotext | PDFをテキストへ変換する機能と終了コード |
| Debian Manpages: pdffonts | emb、sub、uni列が示す情報 |
| Adobe Acrobat: Create and verify PDF accessibility | PDFのアクセシビリティ検査と、人が確認する項目 |
| W3C: PDF16 | PDF文書のデフォルト言語を/Langで指定する方法 |

