PDFのフォントを書き換えたい
久しぶりに日本語の論文を読んでたら、明朝フォント読むのつらたんだったので、PDFを編集する方法を知りたい。
そして明朝体を撲滅したい。読めなくはないけど目が疲れるんですやめてください。
調べたらPyMuPDF
でできそうな雰囲気。
そして直接フォントを変えるのは無理そう?なのでバイナリ書き換え的なことをする必要がありそう?
とりあえず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のフォント指定部分を書き換えたい。
ちなみにReadableで透明文字ありの同じようなPDFを読み込ませると、文字は重ならないけど透明な文字自体は適当な位置に挿入されていた(抽出されたテキストを確認すると透明な文字も含まれていた)。
DocTranslatorだと透明な文字は拾ってなさそう(抽出された文字を出力できないからなんともいえないけど)。
ドキュメント見ると get_texttrace
でレンダリングモード(type
)とかopacityの取得できるって書いてある。
なんだけど、試してみても透明な文字もレンダリングモード0でopacity1なんだけどなんで?
get_text
だと type = 1
で 画像 らしいんだけど、get_texttrace
も画像判定になってるとかないよね?
やっぱりPyMuPDFで見えない文字の判定はできそうにない雰囲気。
データ上はどこかに存在しているはずだからxrefとかを直接触ればできるんだろうけど...