Open6

PDFのフォントを書き換えたい

kiyukakiyuka

久しぶりに日本語の論文を読んでたら、明朝フォント読むのつらたんだったので、PDFを編集する方法を知りたい。
そして明朝体を撲滅したい。読めなくはないけど目が疲れるんですやめてください。

kiyukakiyuka

とりあえずChatGPTにお願いしてみた。PDFを読み込んで新しく作り直している。

コード
import fitz  # PyMuPDF
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, A4
from reportlab.pdfbase.cidfonts import UnicodeCIDFont

# 日本語フォントの登録
pdfmetrics.registerFont(TTFont("BIZ-UDGOTHICR", r"C:\WINDOWS\Fonts\BIZ-UDGOTHICR.TTC"))
pdfmetrics.registerFont(UnicodeCIDFont("HeiseiKakuGo-W5"))

# PDFファイルを開く
input_pdf_path = "input.pdf"
doc = fitz.open(input_pdf_path)

# 新しいPDFを作成
output_pdf_path = "output.pdf"
c = canvas.Canvas(output_pdf_path, pagesize=A4)

for page_number in range(len(doc)):
    page = doc.load_page(page_number)
    text_instances = page.get_text("dict")["blocks"]

    for instance in text_instances:
        if instance["type"] == 0:  # テキスト
            for line in instance["lines"]:
                for span in line["spans"]:
                    x, y = span["bbox"][0], span["bbox"][3]
                    text, size = span["text"], span["size"]

                    # 日本語フォントを使用
                    # c.setFont('HeiseiKakuGo-W5', size)
                    c.setFont("BIZ-UDGOTHICR", size)

                    c.drawString(x, 841.89 - y, text)  # y座標の調整
        elif instance["type"] == 1:  # 画像
            x0, y0, x1, y1 = instance["bbox"]
            matrix = fitz.Matrix(300 / 72, 300 / 72)  # 解像度を300 DPIに設定
            pix = page.get_pixmap(clip=fitz.Rect(x0, y0, x1, y1), matrix=matrix)
            img_file = f'tmp_image/tmp_image{page_number}_{instance["number"]}.png'
            pix.save(img_file)
            c.drawInlineImage(
                img_file, x0, 841.89 - y1, width=x1 - x0, height=y1 - y0
            )  # y座標の調整

    c.showPage()

c.save()

基本的にこれで行けるみたいなんだけど、日本語の論文ってPDFデータおかしいの結構あるんだよね...透明な文字が上に乗っかってるっていうやつ。
このやり方だと、透明な文字も表示されるので文字が重なってしまう。

文字が透明なのかを判定できればいいんだけど、PyMuPDFだとできなさそうだから、できれば直接PDFのフォント指定部分を書き換えたい。

kiyukakiyuka

ちなみにReadableで透明文字ありの同じようなPDFを読み込ませると、文字は重ならないけど透明な文字自体は適当な位置に挿入されていた(抽出されたテキストを確認すると透明な文字も含まれていた)。

DocTranslatorだと透明な文字は拾ってなさそう(抽出された文字を出力できないからなんともいえないけど)。

kiyukakiyuka

ドキュメント見ると get_texttrace でレンダリングモード(type)とかopacityの取得できるって書いてある。
なんだけど、試してみても透明な文字もレンダリングモード0でopacity1なんだけどなんで?

https://pymupdf.readthedocs.io/ja/latest/functions.html#Page.get_texttrace

get_text だと type = 1 で 画像 らしいんだけど、get_texttrace も画像判定になってるとかないよね?

https://pymupdf.readthedocs.io/ja/latest/textpage.html#page-dictionary

kiyukakiyuka

やっぱりPyMuPDFで見えない文字の判定はできそうにない雰囲気。
データ上はどこかに存在しているはずだからxrefとかを直接触ればできるんだろうけど...