Skip to content

feat: base へ poppler-utils と python3 の画像・XML パッケージを足す(LibreOffice は入れない) #160

Description

@takemi-ohama

何を見つけたか

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:latest7.09GBdocker 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 を取得する(numpyonnxruntime が大きい)。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-skillsclean.pyoffice/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.pyoffice/validate.pysoffice を参照しないので 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:7FROM 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=jaWenQuanYi 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/design/v3.7.0-base-rendering / 計画: issues/PLAN63_base-image-rendering-design.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
  • 計画
  • 実装
  • 構造改善
  • 実装レビュー
  • 完了判定
  • Pull Request — 2026-09-22 07:06
  • 確定仕様化
  • 後片付け
  • 配布
  • 体裁レビュー
  • リリース後テスト
  • 振り返り

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions