pdf2html: CMYK-блоки с ext=png на деле JPEG — декодировать через Pixmap
На «Запускаем Ansible» 3-го изд. 10 из 593 картинок — блоки с b["ext"]=="png" и colorspace=4, но реальные байты — CMYK JPEG (FFD8, подтверждено file). Запись b["image"] как есть под именем .png давала файл, который pngquant и часть читалок отказывались декодировать. _image_png() декодирует сырые байты через pymupdf.Pixmap (MuPDF определяет формат по содержимому, не по чужому ext), при colorspace не Gray/RGB конвертирует в RGB, и всегда отдаёт настоящий PNG. На отказе декодирования — откат к исходным байтам, не падать. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+21
-1
@@ -45,6 +45,26 @@ SOFT_HYPHEN = "\u00ad"
|
||||
OCR = False
|
||||
|
||||
|
||||
def _image_png(raw):
|
||||
"""Байты картинки блока -> настоящий PNG.
|
||||
|
||||
b["ext"] врёт: на «Запускаем Ansible» 3-го изд. блоки с ext="png" и
|
||||
colorspace=4 на деле — CMYK JPEG (magic FFD8, подтверждено `file`), и
|
||||
PNG-инструменты (pngquant) отказываются их декодировать с именем .png.
|
||||
Вместо доверия заявленному формату декодируем через Pixmap (MuPDF сам
|
||||
распознаёт реальный формат по данным) и всегда отдаём RGB PNG — тогда
|
||||
имя файла (.png) не расходится с содержимым и CMYK не ловит инверсию
|
||||
цвета в читалках, которые не ждут Adobe-JPEG с четырьмя каналами.
|
||||
"""
|
||||
try:
|
||||
pix = pymupdf.Pixmap(raw)
|
||||
if pix.colorspace is not None and pix.colorspace.n not in (1, 3):
|
||||
pix = pymupdf.Pixmap(pymupdf.csRGB, pix)
|
||||
return pix.tobytes("png")
|
||||
except Exception:
|
||||
return raw # не смогли декодировать — пишем как есть, лучше так, чем ничего
|
||||
|
||||
|
||||
def style(font, flags=0):
|
||||
"""Полужирный и курсив: сначала флаги, затем имя — имена бывают пустыми."""
|
||||
f = font.lower()
|
||||
@@ -330,7 +350,7 @@ for pno, page in enumerate(doc):
|
||||
continue # подложка отсканированной полосы: текст берём из OCR-слоя
|
||||
img_n += 1
|
||||
name = "img%02d.png" % img_n
|
||||
(IMGDIR / name).write_bytes(b["image"])
|
||||
(IMGDIR / name).write_bytes(_image_png(b["image"]))
|
||||
if open_para:
|
||||
parts.append(open_para)
|
||||
open_para = None
|
||||
|
||||
Reference in New Issue
Block a user