Repository navigation
feat: base へ poppler-utils と python3 の画像・XML パッケージを足す(LibreOffice は入れない) #160
Description
何を見つけたか
base コンテナに、Office 文書を画像へ描画する経路が1つも無い。 document-skills(pptx / docx / xlsx / pdf)の視覚 QA は soffice --headless --convert-to pdf で PDF にし、pdftoppm で画像にする手順だが、その両方が入っていない。
devbase-base:latest(Ubuntu 26.04 / arm64)での実測。
| コマンド / モジュール | 状態 |
|---|---|
soffice / libreoffice |
なし |
pdftoppm / pdftocairo |
なし |
gs / convert / mutool / qpdf |
なし |
python3 の PIL / defusedxml / lxml |
なし |
pip / pip3 |
なし(uv はある) |
gws(@googleworkspace/cli) |
あり |
そのため、スライドを作っても出来上がりを目視で確認できない。 文字のはみ出し・要素の重なり・表と枠の衝突は、レンダリングしないと分からない。
どこで見つけたか
volareinc/nyle-dx の PR #5(経営会議向けスライド11ページ)を作る過程。既存の document-skills:pptx の QA 手順が丸ごと通らなかったため、Google Slides へ変換して gws slides presentations pages getThumbnail でサムネイルを取るという迂回で凌いだ。
この迂回は結果的に精度が高い(配布する実物を見るため、フォント代替による幅ズレが起きない)が、Google アカウントとネットワークが要る。 オフラインでも文書を作る作業では通らない。
実測
追加サイズ
devbase-base:latest は 7.09GB(docker images のディスク使用量。コンテンツのサイズは 2.04GB)。これに対する比率を併記する。
下の追加サイズは起票時に Ubuntu 26.04 / arm64 の apt-get install --no-install-recommends の依存解決から算出した値で、その後のイメージのビルドでは再測していない。
| セット | 追加パッケージ | 展開 | ダウンロード | base 比 |
|---|---|---|---|---|
poppler-utils |
14 | 9.0 MB | 2.7 MB | +0.1% |
python3-pil python3-defusedxml python3-lxml |
18 | 12.2 MB | 3.4 MB | +0.2% |
libreoffice-impress のみ |
78 | 372.1 MB | 101.8 MB | +5.2% |
libreoffice-impress + -writer + -calc |
90 | 458.6 MB | 122.7 MB | +6.5% |
libreoffice(メタ) |
98 | 475.0 MB | 126.4 MB | +6.7% |
fonts-crosextra-carlito + -caladea |
2 | 3.0 MB | 0.9 MB | +0.04% |
大きいのは libreoffice-core 149.9 MB、libreoffice-common 46.5 MB、libicu78 38.0 MB、iso-codes 23.5 MB。libreoffice メタと impress+writer+calc の差は 16 MB しかない。
提案する 6 パッケージは Ubuntu 26.04 arm64 にすべて存在する(poppler-utils 26.01.0-2ubuntu0.1 / python3-pil 12.1.1-2ubuntu1.3 / python3-defusedxml 0.7.1-3build1 / python3-lxml 6.0.2-1build1 / fonts-crosextra-carlito 20230309-2 / fonts-crosextra-caladea 20200211-2)。
動作の検証
poppler-utils python3-pil python3-defusedxml python3-lxml libreoffice-impress を稼働中のコンテナへ入れて(イメージではない)、11ページの日本語スライドで通した。
$ soffice --headless --norestore --convert-to pdf deck.pptx
convert deck.pptx as a Impress document -> deck.pdf using filter : impress_pdf_Export
real 0m0.616s
$ pdfinfo deck.pdf | grep Pages
Pages: 11
$ pdftoppm -jpeg -r 100 deck.pdf slide && ls slide-*.jpg | wc -l
11
通った。 画像も日本語が正しく出た。追加された展開サイズの実測は 381.8 MB(86パッケージ)。
フォント代替が起きる
指定した書体がコンテナに無いと、字幅の違う書体へ置き換わる。 今回のスライドは Zen Kaku Gothic New を指定していたが、PDF に埋め込まれたのは NotoSansCJKsc だった。
$ pdffonts deck.pdf
CAAAAA+NotoSansCJKsc-Bold Type 1 Builtin yes yes yes
DAAAAA+NotoSansCJKsc-Regular Type 1 Builtin yes yes yes
scは簡体字中国語のフェイスである。 日本語の資料でも、既定では JP ではなく SC へ落ちる- 字幅が違うため、Google Slides の実物では1行に収まっていた表の見出しが、この描画では2行に折り返した。「はみ出している」という QA の判定が実物と一致しない
document-skills:pptx の Typography 節は「代替フォントの幅が違うため QA の text-fit は当てにならない」と警告しており、その状態がそのまま起きる。
欧文側も同じである。 同 skill が「安全」とする Calibri と Cambria の metric 互換フォント(fonts-crosextra-carlito / fonts-crosextra-caladea)が入っていない。この2つは合計 3.0 MB で、入れると欧文の折り返し判定が信用できるようになる。fonts-liberation(Arial / Times New Roman の互換)は既に入っている。
markitdown は焼き込まなくてよい
内容の QA(markitdown deck.pptx)は uv で賄える。base に uv があるため追加は要らない(containers/base/Dockerfile の 135 行目と 189 行目で astral.sh から導入している)。
$ uvx --from 'markitdown[pptx]' markitdown deck.pptx
Installed 24 packages in 25ms
<!-- Slide number: 1 -->
初回だけ約45MB を取得する(numpy と onnxruntime が大きい)。2回目以降はキャッシュが効く。焼き込むと展開で 200MB 前後になるため、uvx のままがよい。
python3-pptx は apt に無い。必要になったら uv で入れる。
何をするか
LibreOffice は base に入れない(決定)。 展開 372〜459 MB は base の規律に見合わない。上の実測は、その判断の材料として残す。
base へ入れるもの
poppler-utils
python3-pil python3-defusedxml python3-lxml
fonts-crosextra-carlito fonts-crosextra-caladea
展開 約24 MB / ダウンロード 約7 MB、7.09GB の base に対して +0.34%。
| パッケージ | 何ができるようになるか |
|---|---|
poppler-utils |
PDF を画像にする。PDF のページ数・寸法・埋め込み書体を調べる(pdfinfo / pdffonts)。Office 文書に限らず出る作業 |
python3-pil python3-defusedxml python3-lxml |
document-skills の clean.py と office/validate.py が動く。OOXML を壊さずに読み書きできる(defusedxml を使わないと名前空間が壊れる) |
fonts-crosextra-carlito -caladea |
Calibri / Cambria の metric 互換フォント。欧文の字幅が正しくなる。fonts-liberation(Arial / Times 互換)は既に入っている |
thumbnail.py はこれだけでは動かない。 office.soffice.run_soffice を import して LibreOffice を必ず呼ぶため、LibreOffice を base に入れない以上、動くのは派生イメージ(下の案 A)の側である。clean.py と office/validate.py は soffice を参照しないので base で動く。
pip は足さない。uv があるため、必要な Python パッケージはそちらで賄う。
Office 文書を画像にする経路をどうするか
base に入れない以上、この経路は base の外に置く。 候補は3つある。
| 案 | 形 | base への負担 | 制約 |
|---|---|---|---|
| A | 派生イメージに置く(containers/docs を新設、または containers/latex を文書系として広げる) |
0。そのプロジェクトだけが払う | containers/latex が同じ形の先例(FROM devbase-base:latest + TeX Live) |
| B | 使い捨てコンテナで都度変換する | 0。初回だけ pull | base に docker-ce があるため成立する。イメージの選定と保守が要る |
| C | Google Slides へ変換して確認する | 0 | gws(@googleworkspace/cli)が base にある。Google アカウントとネットワークが要る |
A を推す。 containers/latex という先例があり(containers/latex/Dockerfile:7 が FROM devbase-base:latest)、文書を作るプロジェクトだけが 372〜459 MB を払う形になる。devbase build <image> は $DEVBASE_ROOT/containers/<image> を汎用に建ててタグを devbase-<ディレクトリ名> にするため、containers/docs の新設に本体側の登録変更は要らない。
C はサイズ 0 で、しかも精度が高い。 配布する実物を見るため、書体の代替による字幅のずれが起きない。ただし Google アカウントが要るため、単独の解にはならない。実案件(volareinc/nyle-dx PR #5)ではこの手で11ページを確認した。
前提として直したいこと
日本語が中国語のフォントで描画される問題が別にある(#161)。 fc-match sans-serif:lang=ja が WenQuanYi Zen Hei を返す状態は v3.6.0 の base イメージでも再現する。この状態では、どの経路で描画しても日本語の字形と字幅が正しくない。 追加パッケージ 0(/etc/fonts/local.conf を1つ置く)で直り、検証済みである。描画の道具を足す前に、こちらを先に直したい。
#161 と本件は containers/base/Dockerfile の同じ apt / COPY の区画を触る。#161 を先に入れるか、1 本の PR にまとめる。
修正レイヤー
現象レイヤー: スライドや文書を作っても出来上がりを目視で確認できない(document-skills の QA 手順が丸ごと通らない)。
修正レイヤー: 2 層に分かれる。
| 層 | 対象 | 直す場所 |
|---|---|---|
| 軽量の道具 | poppler-utils / python3-pil / python3-defusedxml / python3-lxml / crosextra 2 種 |
containers/base/Dockerfile の apt 行 |
| Office から画像への経路 | LibreOffice | base の外。containers/docs の新設(containers/latex と同じ FROM devbase-base:latest の形) |
採る手: 新設(containers/docs)。軽量の道具の側は既存の apt 行への追加で、層の移動は伴わない。
由来
volareinc/nyle-dx PR #5 / devbasex/ai-plugins #530
進行
モード: standard / 作業ツリー: .worktrees/feature/v3.7.0-base-rendering / 計画: issues/PLAN63_base-image-rendering-impl.md
- 要求と受け入れ条件 — 2026-09-22 06:49
- 作業場所の用意 — 2026-09-22 06:50
- 設計 — 2026-09-22 06:57
- 素材の収集と出典の確定
- ドキュメント再構成 — 2026-09-22 07:02
- ドキュメントレビュー — 2026-09-22 07:05
- 計画 — 2026-09-23 04:09
- 実装 — 2026-09-23 04:09
- 構造改善 — 2026-09-23 04:28
- 実装レビュー — 2026-09-23 04:40
- 完了判定 — 2026-09-23 05:17
- Pull Request — 2026-09-22 07:06
- 確定仕様化 — 2026-09-23 05:25
- 後片付け — 2026-09-23 04:06
- 配布 — 2026-09-23 06:02
- 体裁レビュー
- リリース後テスト — 2026-09-23 07:53
- 振り返り — 2026-09-23 08:08
振り返り: #212 (comment)
Activity
[-]feat: base コンテナに Office 文書を画像へ描画する経路が無く、スライドの目視確認ができない[/-][+]feat: base へ poppler-utils と python3 の画像・XML パッケージを足す(LibreOffice は入れない)[/+]takemi-ohama commentedon Sep 9, 2026
LibreOffice はサイズが見合わないため、base には入れない方針になった。本文の「何をするか」を差し替えた。実測は判断の材料として残してある。
poppler-utils+python3-pil/-defusedxml/-lxml+ metric 互換フォント2つ。展開 約24 MB / +0.35%containers/latexの先例に倣って派生イメージへ置く案を推す検証のためこのコンテナへ入れていた LibreOffice は削除済み。
takemi-ohama commentedon Sep 21, 2026
PLAN63(#161 と 1 本にまとめた設計)の範囲を base への追加に限ったため、案 A(
containers/docsの新設)は範囲外と判断し、#219 として残した。案 A・B・C の比較と LibreOffice の実測表を引き写してある。docs(PLAN63): base イメージの日本語の描画と、文書を扱う軽量の道具の要求仕様と設計 (#161, #160) (#221)
feat(PLAN63): base イメージの日本語の描画を直し、文書を扱う軽量の道具を足す (#161, #160)
feat(PLAN63): base イメージの日本語の描画を直し、文書を扱う軽量の道具を足す (#161, #160) (#238)
docs: PLAN63 / PLAN64 / PLAN65 / PLAN66 を確定仕様へ取り込む (#161, #160, #188, #…