以下の内容はhttps://kmuto.hatenablog.com/entry/2025/11/23/111400より取得しました。


スライドホスティングサイトでの文字化けの悩みをさらに調べていたら、より良さそうな対処方法を発見した

昨日はスライドホスティングサイトの文字化け・文字落ちの対処としてPDFの画像化・透明文字埋め込みの変換をするPDF Slide Guardを作っていた。

kmuto.hatenablog.com

「そもそも何でこの文字化けが起きるんだ?」と掘っていった結果、(少なくとも今対象にしているケースでは)QPDFで修復できることがわかった。

qpdf --qdf 元PDFファイル 修復後PDFファイル だけで治り、画像化によるサイズ問題や埋め込みテキストの消失も考えなくてよい。Dockerイメージも一応用意したよ。

Ghostscriptによる調査

壊れるPDFはそもそも何らかおかしいと思われるので、リファレンスとしてGhostscriptで見てみるところから始めた。以下はPDF original.pdfを読み込んでPDF g.pdfを書き込むという処理である。

$ gs -sDEVICE=pdfwrite -o g.pdf original.pdf
GPL Ghostscript 10.05.1 (2025-04-29)
Copyright (C) 2025 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
 ...
Page 6
GPL Ghostscript 10.05.1: Missing glyph CID=0, glyph=6201 in the font MUFUZY+MPLUS2-Bold . The output PDF may fail with some viewers.
Page 7
 ...

The following errors were encountered at least once while processing this file:
    Attempt to dereference a free object

   **** This file had errors that were repaired or ignored.
   **** Please notify the author of the software that produced this
   **** file that it does not conform to Adobe's published PDF
   **** specification.
$

いかにも怪しいメッセージが出てきた。g.pdfを見ると、該当箇所のtofu化が起きている。

Ghostscript経由でtofu化した

症状としては以下のようになっているのだろう。

  1. GoogleスライドでM Plus和文フォントを使って文字を入れた
  2. スライドでPDF書き出しを選び、Google側がPDF変換を行った
  3. このとき、M Plus和文フォント全部ではなくサブセットフォントが作られ、埋め込まれた
  4. Ghostscriptは「CID=0, glyph=6201」はグリフ(字形)ID 6201について、文字コード(CID)がゼロまたは無効な参照になっていることを検知した。つまりグリフIDとCIDの対応関係が何かおかしなことになっている(ほかのビューア、PopplerやMuPDFなどは何らか寛容にできる仕組みがある? フォールバックしているという見た目でもないし)
  5. Ghostscriptは無効部分をtofuなどの表示とした

各ページでの欠落箇所はSpeaker Deckと同じであり、Speaker DeckでもおそらくGhostscriptかそれに類似したエンジンを使っていると推測する。

GhostscriptでPDFを扱う時点で壊れているので、Ghostscriptを使うアウトライン化(-dNoOutputFonts)やPostScript化(-sDEVICE=ps2write)は効果がない。

CIDチェックの無視(-dUseCICP=false)、互換性レベル(-dCompatibilityLevel)、事前処理(-dPDFSETTINGS=/prepress)、CJKオプションまわり(-dCIDfmap=false)も効き目はなかった。

QPDFによる修復

フォント構造のところでおかしいことはわかったので、PDFの正規化を試みることにする。そのような用途には、QPDFというツールがある。

qpdf.sourceforge.io

QPDFは多才で修復にもたくさんのオプションがあり、試行錯誤していたのだが、結論としてはQDF形式(非圧縮・リニア)に正規化し直す--qdfオプションだけでよい(しばらく--qpdfとタイプしてはエラーになって悩んでいた)。

以下はPDF original.pdfを読み込んで、正規化したPDF q.pdfを書き込む例である。

$ qpdf --qdf original.pdf q.pdf

Ghostscriptに通してみる。

$ gs -sDEVICE=pdfwrite -o g.pdf q.pdf
GPL Ghostscript 10.05.1 (2025-04-29)
Copyright (C) 2025 Artifex Software, Inc.  All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
 ...
Page 6
Page 7
 ...
$

つつがなく終わった。g.pdfを表示してみよう。

tofu化せずに正常に変換されている

Speaker Deckに正規化済みのq.pdfをテスト投稿してみる。

正規化済みPDFではSpeaker Deckでも壊れずに表示された

やったぜ。

Dockerイメージの提供

qpdfを単に実行するだけなのでDockerイメージ化するほどでもない気はするが、Docker Hubのkenshimuto/qpdfに作っておいた。

https://hub.docker.com/r/kenshimuto/qpdfhub.docker.com

中身としては、以下のとおり本当にqpdfコマンドを実行しているだけである。

#!/bin/sh
qpdf --qdf $1 $2
FROM debian:trixie-slim
ENV LANG=en_US.UTF-8
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
  && apt-get install -y --no-install-recommends qpdf \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*
COPY ./fix-pdf /usr/bin/fix-pdf
RUN chmod a+x /usr/bin/fix-pdf
ENTRYPOINT ["fix-pdf"]



以上の内容はhttps://kmuto.hatenablog.com/entry/2025/11/23/111400より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14