vivlio-starter-pdf 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/CHANGELOG.md +23 -10
- data/README.md +14 -4
- data/RELEASE_NOTE.md +34 -112
- data/Rakefile +52 -5
- data/lib/vivlio_starter/cli/pdf/outline_writer.rb +35 -6
- data/lib/vivlio_starter/cli/pdf/version.rb +1 -1
- data/vivlio-starter-pdf.gemspec +6 -4
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0335b9ec25ee9a373f9d4c261c1a4a610e87fb2ac538b2207b3dd8f741bc82c1
|
|
4
|
+
data.tar.gz: 9645fdbcb4575cae982bf48ef0c60f061b6f26afbbe101bd4530f95262c6da32
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 01f2c370439f11cf3012f32b092415a8aeebab059386f09462292952e7026b8b616db82e00aae11489465d562c0f90f89ea548f6df98d89523e05c7b0f1e8a00
|
|
7
|
+
data.tar.gz: 215ff34974f8bc3f2fd81f929bd39413ff79ad454db5993ee36c350dd48af12b091372b9b1ca42c6b048e29d5633e88b29bfb5dca3aebcaa8726d4d594773f4e
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.0.6
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
### Planned
|
|
9
|
+
- パフォーマンス最適化(大規模 PDF 対応)
|
|
10
|
+
- 追加 OCR エンジン対応
|
|
11
|
+
- クラウド OCR サービス連携
|
|
12
|
+
- PDF 暗号化対応
|
|
13
|
+
|
|
14
|
+
## [1.1.2] - 2026-08-07
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **必要な Ruby を 4.0 以上から 3.4 以上へ緩めた** (`vivlio-starter-pdf.gemspec`): Ruby 4.0 固有の機能は使っていない。Prism のバージョン指定パースで全 13 ファイルを解析したところ 4.0.0 / 3.4.0 / 3.3.0 いずれも構文エラー 0 件で、実際の下限を決めていたのは `it`(暗黙ブロック引数・38 箇所)**単独**だった。`it` は 3.3 でも構文エラーにならず実行時 `NameError` になる——静的解析では見つからないので、Ruby 3.4.10 で実走して全テスト通過を確認している。コード変更はゼロ(gemspec 1 行のみ)。本体 `vivlio-starter` の緩和に合わせたもので、本体だけ緩めてもプラグインが `>= 4.0` のままでは 3.4 環境に入らない。
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **壊れたアウトライン項目 1 件が、しおりを全滅させていたのを直した** (`outline_writer.rb`): 見出しのタイトルに不正な UTF-8 バイトが混ざると `String#strip` が `Encoding::CompatibilityError` を投げ、`add_outline!` の rescue まで飛んで **PDF からしおりが丸ごと消えていた**。範囲外ページ・空タイトル・深すぎる階層はいずれも `on_skip` で 1 件ずつ飛ばす設計なのに、ここだけ全体を巻き添えにしていた。
|
|
21
|
+
- `add_outline!` は `false` を返すだけで PDF 自体は出来上がるため、**成果物を開くまで誰も気付けない**種類の失敗だった。
|
|
22
|
+
- 該当項目だけを飛ばし、理由(`title is not valid UTF-8, skipping outline entry: …`)を `on_skip` で報告する。原稿のどの見出しを直せばよいか分かる形にした。
|
|
23
|
+
- `EncodingError` と `ArgumentError` の両方を捕まえる。壊れたバイト列に Ruby がどちらを投げるかはメソッド次第で(`strip` は `Encoding::CompatibilityError`、`match?` は `ArgumentError`)、その差でしおりの有無が決まってはならない。
|
|
24
|
+
- **アウトライン項目に `nil` 以外の想定外の型が混ざると全体が止まっていたのを直した** (`outline_writer.rb`): `fetch` が `respond_to?(:[])` だけで添字アクセスしていたため、配列に `String` や `Integer` が紛れると `TypeError: no implicit conversion of Symbol into Integer`(`Integer#[]` はビット参照)で落ちていた。Hash 風オブジェクトは従来どおり受けつつ、添字アクセスの失敗は既定値へ倒す。
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- **堅牢性テストを整備した** (`test/robustness/`): 本体 `vivlio-starter` の `test/vivlio_starter/robustness/` と同じ位置づけで 14 件を追加。守る約束は 2 つ——**公開 API は例外を外へ出さない**(ビルドパイプラインの途中から呼ばれるため、失敗は戻り値で伝える)、**失敗しても入力を壊さない**(読み込んだのと同じパスへ書き戻すため、途中失敗で元 PDF が切り詰められると最も気付きにくい事故になる)。上記 2 件の修正はこのテストを書く過程で見つかったもの。
|
|
28
|
+
- `broken_pdf_test.rb` — PDF でないファイル・0 バイト・存在しないパス・暗号化 PDF・書き込み不可ファイル。戻り値と、**入力のバイト列が不変であること**を固定
|
|
29
|
+
- `outline_entry_test.rb` — 壊れた項目を 1 件ずつ飛ばして残りを書くこと、飛ばした理由を報告すること、全滅時に空のしおりツリーを残さないこと
|
|
30
|
+
|
|
8
31
|
## [1.1.1] - 2026-06-23
|
|
9
32
|
|
|
10
33
|
### Fixed
|
|
@@ -69,13 +92,3 @@ vivlio-starter-pdf 1.0.0 としてリリース!HexaPDF を活用した高度
|
|
|
69
92
|
- 日本語テキストの空白圧縮処理
|
|
70
93
|
- 括弧の正規化と誤読修正
|
|
71
94
|
- 出版向けの文字処理最適化
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## [Unreleased]
|
|
76
|
-
|
|
77
|
-
### Planned
|
|
78
|
-
- パフォーマンス最適化(大規模 PDF 対応)
|
|
79
|
-
- 追加 OCR エンジン対応
|
|
80
|
-
- クラウド OCR サービス連携
|
|
81
|
-
- PDF 暗号化対応
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# vivlio-starter-pdf
|
|
2
2
|
|
|
3
3
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
4
|
-
[](https://www.ruby-lang.org/)
|
|
5
5
|
|
|
6
6
|
**vivlio-starter** の AGPL 拡張プラグイン。HexaPDF を活用した高度な PDF 解析・後処理機能を提供します。
|
|
7
7
|
|
|
@@ -46,24 +46,34 @@ brew install tesseract tesseract-lang poppler vips
|
|
|
46
46
|
vs pdf:read document.pdf
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
標準(MIT)実装に戻して動作を比べたいときは、環境変数で無効化できます。
|
|
50
|
+
|
|
51
|
+
```zsh
|
|
52
|
+
VIVLIO_PDF_PLUGIN=disable vs build
|
|
53
|
+
```
|
|
54
|
+
|
|
49
55
|
### Ruby API
|
|
50
56
|
|
|
51
57
|
```ruby
|
|
52
|
-
require "
|
|
58
|
+
require "vivlio_starter/pdf"
|
|
53
59
|
|
|
54
60
|
# PDF → Markdown 変換
|
|
55
|
-
result =
|
|
61
|
+
result = VivlioStarter::Pdf::Reader.new("input.pdf",
|
|
56
62
|
ocr: { mode: "auto", languages: ["jpn"], dpi: 300 }
|
|
57
63
|
).execute
|
|
58
64
|
|
|
59
65
|
# アウトライン付与
|
|
60
|
-
provider =
|
|
66
|
+
provider = VivlioStarter::Pdf::EnhancedProvider.new
|
|
61
67
|
provider.add_outline!(pdf_path, items, max_level: 3)
|
|
62
68
|
|
|
63
69
|
# 隠しノンブル
|
|
64
70
|
provider.stamp_nombre!(pdf_path, bleed_pt: 8.5)
|
|
65
71
|
```
|
|
66
72
|
|
|
73
|
+
`stamp_nombre!` / `add_outline!` は成功で `true`、失敗で `false` を返し、`page_count` は失敗で `nil` を返します。**例外は外へ出しません**(本体のビルドパイプラインの途中から呼ばれるため)。失敗しても入力 PDF は書き換えません。
|
|
74
|
+
|
|
75
|
+
`add_outline!` の `items` は `{ level:, text:, page: }` の配列です。壊れた項目(不正な UTF-8 のタイトル・範囲外ページ・空タイトル)は 1 件ずつ飛ばして残りを書き込み、飛ばした理由をログに出します。
|
|
76
|
+
|
|
67
77
|
## 設定
|
|
68
78
|
|
|
69
79
|
`config/book.yml` の `pdf_read` セクションで挙動を制御できます。
|
data/RELEASE_NOTE.md
CHANGED
|
@@ -1,133 +1,55 @@
|
|
|
1
|
-
# vivlio-starter-pdf
|
|
1
|
+
# vivlio-starter-pdf リリースノート
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
書籍制作ツール **vivlio-starter** の AGPL 拡張プラグインです。HexaPDF を使い、隠しノンブル・PDF アウトライン・PDF → Markdown 変換(OCR 連携)を担当します。使い方は [README](README.md)、網羅的な変更履歴は [CHANGELOG](CHANGELOG.md) をご覧ください。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
新しい版から順に並べています。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
### PDF → Markdown 変換
|
|
10
|
-
- HexaPDF でテキスト・画像を高精度に抽出
|
|
11
|
-
- 精密な座標解析による行・段落の再構成
|
|
12
|
-
- Markdown 形式での構造化出力
|
|
13
|
-
|
|
14
|
-
### OCR 連携と日本語対応 🆕
|
|
15
|
-
- スキャン PDF を自動検出
|
|
16
|
-
- Tesseract による日本語 OCR 実行
|
|
17
|
-
- OCR テキストの空白圧縮と括弧正規化
|
|
18
|
-
- prh 辞書による誤読修正
|
|
19
|
-
|
|
20
|
-
### 画像抽出と位置合わせ
|
|
21
|
-
- PDF 内の XObject を解析し、WebP 形式で書き出し
|
|
22
|
-
- テキスト行と画像の精密な座標マッピング
|
|
23
|
-
- イラスト領域の自動検出と除外
|
|
24
|
-
|
|
25
|
-
### 出版向け機能
|
|
26
|
-
- **隠しノンブル**: 入稿用 PDF の塗り足し領域にページ番号をオーバーレイ
|
|
27
|
-
- **PDF アウトライン**: HTML 見出しを解析し、PDF のブックマークツリーを構築
|
|
28
|
-
|
|
29
|
-
## 📦 インストール
|
|
30
|
-
|
|
31
|
-
```ruby
|
|
32
|
-
# Gemfile
|
|
33
|
-
gem 'vivlio-starter-pdf', '~> 1.0.0'
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
bundle install
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### 外部ツール(OCR 利用時)
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
brew install tesseract tesseract-lang poppler vips
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## 💡 使用例
|
|
47
|
-
|
|
48
|
-
### vivlio-starter との連携(プラグイン専用)
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
# Enhanced Mode で自動的に HexaPDF/OCR パイプラインを使用
|
|
52
|
-
vs pdf:read document.pdf
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Ruby API
|
|
56
|
-
|
|
57
|
-
```ruby
|
|
58
|
-
require "vivlio/starter/pdf"
|
|
59
|
-
|
|
60
|
-
# PDF → Markdown 変換
|
|
61
|
-
result = Vivlio::Starter::PDF::Reader.new("input.pdf",
|
|
62
|
-
ocr: { mode: "auto", languages: ["jpn"], dpi: 300 }
|
|
63
|
-
).execute
|
|
7
|
+
---
|
|
64
8
|
|
|
65
|
-
|
|
66
|
-
provider = Vivlio::Starter::Pdf::EnhancedProvider.new
|
|
67
|
-
provider.add_outline!(pdf_path, items, max_level: 3)
|
|
9
|
+
## 1.1.2 — 2026-08-07
|
|
68
10
|
|
|
69
|
-
|
|
70
|
-
provider.stamp_nombre!(pdf_path, bleed_pt: 8.5)
|
|
71
|
-
```
|
|
11
|
+
**細かな不具合修正が中心のリリースです。** ただし 1 件は成果物に直接影響するため、しおり付き PDF を作る方は更新をおすすめします。
|
|
72
12
|
|
|
73
|
-
|
|
13
|
+
- **壊れた見出しが 1 つあると、しおりが丸ごと消えていた問題を直しました。** 見出しに不正な UTF-8 バイトが混ざると例外が最上位まで飛び、**PDF からしおりが全滅**していました。範囲外ページや空タイトルは 1 件ずつ飛ばす設計だったのに、ここだけ全体を巻き添えにしていたことになります。しかも PDF 自体は出来上がるため、**開いてみるまで誰も気付けません**。今は該当項目だけを飛ばし、どの見出しが原因かをログで知らせます
|
|
14
|
+
- **想定外の型が項目に混ざると、アウトライン付与が止まっていた問題を直しました**(`TypeError`)
|
|
15
|
+
- **必要な Ruby を 4.0 以上から 3.4 以上へ緩めました**(コード変更はゼロ、gemspec 1 行のみ)。本体の緩和に合わせたものです。本体だけ緩めても、プラグインが 4.0 以上のままでは 3.4 環境に入りません
|
|
74
16
|
|
|
75
|
-
`
|
|
17
|
+
あわせて、これらを二度と起こさないための**堅牢性テスト 14 件**を `test/robustness/` に追加しました。守る約束は 2 つです。
|
|
76
18
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
text_area:
|
|
80
|
-
top_margin: 18
|
|
81
|
-
bottom_margin: 20
|
|
82
|
-
inner_margin: 15
|
|
83
|
-
outer_margin: 12
|
|
84
|
-
page_separator: false
|
|
85
|
-
ocr:
|
|
86
|
-
mode: auto
|
|
87
|
-
languages:
|
|
88
|
-
- japanese
|
|
89
|
-
dpi: 300
|
|
90
|
-
psm: 3
|
|
91
|
-
inline_image_text: include
|
|
92
|
-
```
|
|
19
|
+
1. **公開 API は例外を外へ出さない。** 本体のビルドパイプラインの途中から呼ばれるため、1 つの PDF 操作が例外で飛ぶとビルド全体が落ちます。失敗は戻り値で伝えます
|
|
20
|
+
2. **失敗しても入力を壊さない。** 読み込んだのと同じパスへ書き戻すので、途中で失敗して元 PDF が切り詰められると「ビルドは続いたのに成果物が壊れている」という最も気付きにくい事故になります
|
|
93
21
|
|
|
94
|
-
|
|
22
|
+
上の 2 件は、このテストを書く過程で見つかりました。
|
|
95
23
|
|
|
96
|
-
-
|
|
97
|
-
- **実環境での動作検証**
|
|
98
|
-
- **外部ツール連携のテスト**
|
|
24
|
+
## 1.1.1 — 2026-06-23
|
|
99
25
|
|
|
100
|
-
|
|
26
|
+
- **隠しノンブルを埋め込み可能なフォントで描画するようにしました(FT-02)。** HexaPDF 組込の標準 14 フォント `Helvetica` は PDF に埋め込まれず、印刷所入稿で「非埋め込みフォント」の差し戻しになっていました
|
|
27
|
+
- 書籍プロジェクト直下に同梱の `stylesheets/fonts/hackgen35/HackGen35ConsoleNF-Regular.ttf` があれば、数字グリフのみをサブセット埋め込みします(増分は極小)。無ければ従来どおり `Helvetica` にフォールバックしてビルドを続けます
|
|
101
28
|
|
|
102
|
-
|
|
103
|
-
- 完全な OCR 連携と日本語対応
|
|
104
|
-
- 画像位置合わせの精密化
|
|
105
|
-
- PDF アウトライン生成機能
|
|
106
|
-
- 隠しノンブル機能
|
|
29
|
+
## 1.1.0 — 2026-06-10
|
|
107
30
|
|
|
108
|
-
|
|
109
|
-
- gemspec の RubyGems 公開設定
|
|
110
|
-
- ドキュメントの整備
|
|
111
|
-
- 外部ツールの自動案内
|
|
31
|
+
- **名前空間を `VivlioStarter::Pdf` へ統一し、`lib/vivlio_starter/` 配下へ再編しました。** 1.0.0 以降で**唯一の非互換変更**です
|
|
112
32
|
|
|
113
|
-
|
|
33
|
+
本体(`vs`)経由で使っている場合、影響はありません。**Ruby API を直接呼んでいる場合のみ**書き換えが必要です。
|
|
114
34
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
35
|
+
| | 1.0.x | 1.1.0 以降 |
|
|
36
|
+
|:---|:---|:---|
|
|
37
|
+
| require | `require "vivlio/starter/pdf"` | `require "vivlio_starter/pdf"` |
|
|
38
|
+
| 名前空間 | `Vivlio::Starter::PDF` と `Vivlio::Starter::Pdf` が混在 | `VivlioStarter::Pdf` に統一 |
|
|
119
39
|
|
|
120
|
-
|
|
40
|
+
1.0.x では `PDF` と `Pdf` の 2 つの綴りが同居しており、どちらを書けばよいか実物を見ないと分からない状態でした。
|
|
121
41
|
|
|
122
|
-
|
|
123
|
-
- **依存**: hexapdf (~> 1.0), ruby-vips (~> 2.2)
|
|
124
|
-
- **外部ツール**: Tesseract, poppler, libvips(OCR 使用時)
|
|
125
|
-
- **セマンティックバージョニング**: 1.x.x 系は後方互換性を保証
|
|
42
|
+
## 1.0.1 — 2026-03-21
|
|
126
43
|
|
|
127
|
-
|
|
44
|
+
- **CLI を追加しました**(`vivlio-starter-pdf --version` / `--help`)。インストール直後に動作確認できます
|
|
128
45
|
|
|
129
|
-
|
|
46
|
+
## 1.0.0 — 2026-03-21
|
|
130
47
|
|
|
131
|
-
|
|
48
|
+
最初のメジャーリリースです。
|
|
132
49
|
|
|
133
|
-
|
|
50
|
+
- **隠しノンブル** — 入稿用 PDF の塗り足し領域に、断裁されて消えるページ番号を刷り込みます
|
|
51
|
+
- **PDF アウトライン** — 見出しから PDF のブックマークツリーを構築します
|
|
52
|
+
- **PDF → Markdown 変換** — HexaPDF でテキスト・画像を座標付きで抽出します
|
|
53
|
+
- **OCR 連携** — スキャン PDF を自動検出し、Tesseract で日本語 OCR を実行。空白圧縮・括弧正規化・prh 辞書による誤読修正まで行います
|
|
54
|
+
- **画像抽出** — PDF 内の XObject を解析し、WebP 形式で書き出します
|
|
55
|
+
- プラグイン専用設計。インストールされていれば本体が自動検出し、Standard Mode から Enhanced Mode へ切り替わります
|
data/Rakefile
CHANGED
|
@@ -3,12 +3,59 @@
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
4
|
require "rake/testtask"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
# gemspec が Ruby 3.4 以上を謳う以上、それが本当かは実際に走らせないと分からない。
|
|
7
|
+
# `it`(暗黙ブロック引数)は 3.3 以下でも構文エラーにならず「it というメソッドの
|
|
8
|
+
# 呼び出し」として通り、実行時に NameError になる——静的解析では捕まらない。
|
|
9
|
+
SUPPORTED_RUBY_VERSIONS = %w[3.4.10 4.0.6].freeze
|
|
10
|
+
|
|
11
|
+
# 別の Ruby を子プロセスで起動する以上、親の bundler 環境は必ず捨てる。
|
|
12
|
+
# `bundle exec rake test` から呼ばれると、親(現在の Ruby)の bundler を
|
|
13
|
+
# 子(別の Ruby)が読みに行き、テストが始まる前に LoadError で落ちる。
|
|
14
|
+
# nil を渡すと、その環境変数は子から取り除かれる。
|
|
15
|
+
UNBUNDLED_ENV = {
|
|
16
|
+
"RUBYOPT" => nil, "RUBYLIB" => nil, "GEM_HOME" => nil, "GEM_PATH" => nil,
|
|
17
|
+
"BUNDLE_GEMFILE" => nil, "BUNDLE_BIN_PATH" => nil, "BUNDLER_VERSION" => nil,
|
|
18
|
+
"BUNDLER_SETUP" => nil
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
namespace :test do
|
|
22
|
+
# テストの実体。現在の Ruby で 1 回だけ走る(test:versions が各版でこれを呼ぶ)
|
|
23
|
+
Rake::TestTask.new(:current) do |t|
|
|
24
|
+
t.libs << "test"
|
|
25
|
+
t.libs << "lib"
|
|
26
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
desc "対応する全 Ruby 版(#{SUPPORTED_RUBY_VERSIONS.join(' / ')})でテストする"
|
|
30
|
+
task :versions do
|
|
31
|
+
missing = SUPPORTED_RUBY_VERSIONS - `rbenv versions --bare`.split("\n")
|
|
32
|
+
unless missing.empty?
|
|
33
|
+
abort <<~MESSAGE
|
|
34
|
+
次の Ruby が rbenv に入っていません: #{missing.join(', ')}
|
|
35
|
+
#{missing.map { "rbenv install #{it}" }.join("\n ")}
|
|
36
|
+
MESSAGE
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# 版ごとに bundle が要る。未導入なら黙って入れる(その版の初回だけ時間がかかる)
|
|
40
|
+
failed = SUPPORTED_RUBY_VERSIONS.reject do |version|
|
|
41
|
+
puts "\n=== Ruby #{version} ==="
|
|
42
|
+
env = UNBUNDLED_ENV.merge("RBENV_VERSION" => version)
|
|
43
|
+
|
|
44
|
+
unless system(env, "rbenv exec bundle check", out: File::NULL, err: File::NULL)
|
|
45
|
+
next false unless system(env, "rbenv exec bundle install --quiet")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
system(env, "rbenv exec bundle exec rake test:current")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
abort "\n失敗した Ruby: #{failed.join(', ')}" unless failed.empty?
|
|
52
|
+
puts "\n全 Ruby 版で通過: #{SUPPORTED_RUBY_VERSIONS.join(' / ')}"
|
|
53
|
+
end
|
|
10
54
|
end
|
|
11
55
|
|
|
56
|
+
# 手元では常に対応全版を回す(1 版あたり 10 秒弱で終わるため、分けるほどの負担にならない)。
|
|
57
|
+
# CI(GitHub Actions)は版をマトリクスで分担するので、各ジョブは 1 回でよい。
|
|
58
|
+
task test: (ENV["CI"] ? "test:current" : "test:versions")
|
|
12
59
|
task default: :test
|
|
13
60
|
|
|
14
61
|
# gem のアンインストール → ビルド → インストールを一括実行
|
|
@@ -16,7 +63,7 @@ task :reinstall do
|
|
|
16
63
|
gemspec = Dir['*.gemspec'].first
|
|
17
64
|
raise 'gemspec が見つかりません' unless gemspec
|
|
18
65
|
|
|
19
|
-
require_relative 'lib/vivlio_starter/pdf/version'
|
|
66
|
+
require_relative 'lib/vivlio_starter/cli/pdf/version'
|
|
20
67
|
version = VivlioStarter::Pdf::VERSION
|
|
21
68
|
gem_name = 'vivlio-starter-pdf'
|
|
22
69
|
gem_file = "#{gem_name}-#{version}.gem"
|
|
@@ -54,7 +54,9 @@ module VivlioStarter
|
|
|
54
54
|
|
|
55
55
|
# Normalizes a raw hash into a consistent entry structure.
|
|
56
56
|
def normalize_entry(raw)
|
|
57
|
-
text =
|
|
57
|
+
text = entry_title(raw)
|
|
58
|
+
return nil if text.nil?
|
|
59
|
+
|
|
58
60
|
warn_skip("missing title for outline entry: #{raw.inspect}") if text.empty?
|
|
59
61
|
return nil if text.empty?
|
|
60
62
|
|
|
@@ -71,13 +73,40 @@ module VivlioStarter
|
|
|
71
73
|
{ text:, page:, level: }
|
|
72
74
|
end
|
|
73
75
|
|
|
76
|
+
# Returns the trimmed title, or +nil+ when the entry must be skipped.
|
|
77
|
+
#
|
|
78
|
+
# A title carrying invalid UTF-8 bytes makes +String#strip+ raise
|
|
79
|
+
# +Encoding::CompatibilityError: invalid byte sequence in UTF-8+. Letting that
|
|
80
|
+
# escape costs the *entire* outline: +add_outline!+ rescues at the top, so one
|
|
81
|
+
# mojibake heading would leave the book with no bookmarks at all. Every other
|
|
82
|
+
# kind of bad entry is skipped one by one through +on_skip+ — this one must
|
|
83
|
+
# behave the same way, and the message has to name the entry so the author can
|
|
84
|
+
# fix the manuscript heading that produced it.
|
|
85
|
+
#
|
|
86
|
+
# Both +EncodingError+ and +ArgumentError+ are caught on purpose: which one
|
|
87
|
+
# Ruby raises for broken bytes depends on the method (+strip+ raises
|
|
88
|
+
# +Encoding::CompatibilityError+, +match?+ raises +ArgumentError+), and that
|
|
89
|
+
# detail must not decide whether the book keeps its bookmarks.
|
|
90
|
+
def entry_title(raw)
|
|
91
|
+
fetch(raw, :text, fetch(raw, :title, nil)).to_s.strip
|
|
92
|
+
rescue EncodingError, ArgumentError
|
|
93
|
+
# +inspect+ is safe here: it escapes invalid bytes (\xFF) instead of raising.
|
|
94
|
+
warn_skip("title is not valid UTF-8, skipping outline entry: #{raw.inspect}")
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
74
98
|
# Fetches a value from the entry by symbol or string key.
|
|
99
|
+
#
|
|
100
|
+
# Entries come from the caller, so a stray String or Integer can end up in the
|
|
101
|
+
# array. Both answer +respond_to?(:[])+ but raise +TypeError+ when indexed with
|
|
102
|
+
# a Symbol (+Integer#[]+ is bit access), which would abort the whole outline —
|
|
103
|
+
# exactly what the per-entry skip exists to prevent. Duck typing is kept so a
|
|
104
|
+
# Hash-like object still works; only the indexing failure falls back.
|
|
75
105
|
def fetch(raw, key, fallback)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
end
|
|
106
|
+
value = (raw[key] || raw[key.to_s] if raw.respond_to?(:[]))
|
|
107
|
+
value.nil? ? fallback : value
|
|
108
|
+
rescue TypeError
|
|
109
|
+
fallback
|
|
81
110
|
end
|
|
82
111
|
|
|
83
112
|
# Returns the proper parent node for the requested level.
|
data/vivlio-starter-pdf.gemspec
CHANGED
|
@@ -5,18 +5,20 @@ require_relative "lib/vivlio_starter/cli/pdf/version"
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "vivlio-starter-pdf"
|
|
7
7
|
spec.version = VivlioStarter::Pdf::VERSION
|
|
8
|
-
spec.authors = ["Mirai"]
|
|
9
|
-
spec.email = ["mirai
|
|
8
|
+
spec.authors = ["Atelier Mirai"]
|
|
9
|
+
spec.email = ["contact@atelier-mirai.net"]
|
|
10
10
|
|
|
11
11
|
spec.summary = "Advanced PDF processor for vivlio-starter using HexaPDF"
|
|
12
12
|
spec.description = "Provides PDF outline extraction, precision page numbering, and OCR via HexaPDF. AGPL-3.0 licensed."
|
|
13
13
|
spec.homepage = "https://github.com/Atelier-Mirai/vivlio-starter-pdf"
|
|
14
14
|
spec.license = "AGPL-3.0-only"
|
|
15
|
-
spec.required_ruby_version = ">= 4.0
|
|
15
|
+
spec.required_ruby_version = ">= 3.4.0"
|
|
16
16
|
|
|
17
|
+
# homepage_uri は spec.homepage から自動で作られる。metadata にも同じ URL を書くと
|
|
18
|
+
# rubygems.org はどちらか片方しか表示せず、gem build が警告を出す
|
|
17
19
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
18
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
20
|
spec.metadata["source_code_uri"] = "https://github.com/Atelier-Mirai/vivlio-starter-pdf"
|
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/Atelier-Mirai/vivlio-starter-pdf/blob/master/CHANGELOG.md"
|
|
20
22
|
spec.post_install_message = <<~MESSAGE
|
|
21
23
|
[vivlio-starter-pdf]
|
|
22
24
|
Enhanced Mode の OCR には外部ツール(tesseract / tesseract-lang / poppler / vips)が必要です。
|
metadata
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vivlio-starter-pdf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- Mirai
|
|
7
|
+
- Atelier Mirai
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -82,12 +82,13 @@ dependencies:
|
|
|
82
82
|
description: Provides PDF outline extraction, precision page numbering, and OCR via
|
|
83
83
|
HexaPDF. AGPL-3.0 licensed.
|
|
84
84
|
email:
|
|
85
|
-
- mirai
|
|
85
|
+
- contact@atelier-mirai.net
|
|
86
86
|
executables:
|
|
87
87
|
- vivlio-starter-pdf
|
|
88
88
|
extensions: []
|
|
89
89
|
extra_rdoc_files: []
|
|
90
90
|
files:
|
|
91
|
+
- ".ruby-version"
|
|
91
92
|
- CHANGELOG.md
|
|
92
93
|
- LICENSE
|
|
93
94
|
- README.md
|
|
@@ -107,8 +108,8 @@ licenses:
|
|
|
107
108
|
- AGPL-3.0-only
|
|
108
109
|
metadata:
|
|
109
110
|
allowed_push_host: https://rubygems.org
|
|
110
|
-
homepage_uri: https://github.com/Atelier-Mirai/vivlio-starter-pdf
|
|
111
111
|
source_code_uri: https://github.com/Atelier-Mirai/vivlio-starter-pdf
|
|
112
|
+
changelog_uri: https://github.com/Atelier-Mirai/vivlio-starter-pdf/blob/master/CHANGELOG.md
|
|
112
113
|
post_install_message: |
|
|
113
114
|
[vivlio-starter-pdf]
|
|
114
115
|
Enhanced Mode の OCR には外部ツール(tesseract / tesseract-lang / poppler / vips)が必要です。
|
|
@@ -124,14 +125,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
124
125
|
requirements:
|
|
125
126
|
- - ">="
|
|
126
127
|
- !ruby/object:Gem::Version
|
|
127
|
-
version: 4.0
|
|
128
|
+
version: 3.4.0
|
|
128
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
130
|
requirements:
|
|
130
131
|
- - ">="
|
|
131
132
|
- !ruby/object:Gem::Version
|
|
132
133
|
version: '0'
|
|
133
134
|
requirements: []
|
|
134
|
-
rubygems_version: 4.0.
|
|
135
|
+
rubygems_version: 4.0.16
|
|
135
136
|
specification_version: 4
|
|
136
137
|
summary: Advanced PDF processor for vivlio-starter using HexaPDF
|
|
137
138
|
test_files: []
|