68 lines
3.1 KiB
Python
68 lines
3.1 KiB
Python
|
|
"""Shared fixtures: synthetic formula images and a minimal epub2md output directory."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
import shutil
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import cv2
|
||
|
|
import numpy as np
|
||
|
|
import pytest
|
||
|
|
from PIL import Image
|
||
|
|
|
||
|
|
from formula_img2latex.render import render_many
|
||
|
|
|
||
|
|
needs_latex = pytest.mark.skipif(shutil.which("pdflatex") is None, reason="pdflatex fehlt")
|
||
|
|
needs_pandoc = pytest.mark.skipif(shutil.which("pandoc") is None, reason="pandoc fehlt")
|
||
|
|
|
||
|
|
|
||
|
|
def synth_image(tex: str, display: bool = False, px_per_pt: float = 1.41, fmt: str = "JPEG",
|
||
|
|
offset: tuple[int, int] = (1, 2), preset: str = "cm") -> bytes:
|
||
|
|
"""Render *tex* like a small e-book formula image (Gehrke-like: ~1.4 px/pt, JPEG)."""
|
||
|
|
r = render_many([(tex, display)], preset)[0]
|
||
|
|
assert r.ok, r.error
|
||
|
|
gray = 1.0 - r.rasterize(px_per_pt * 4)
|
||
|
|
pad = np.ones((gray.shape[0] + 8, gray.shape[1] + 8), np.float32)
|
||
|
|
oy, ox = offset
|
||
|
|
pad[oy:oy + gray.shape[0], ox:ox + gray.shape[1]] = gray
|
||
|
|
h, w = pad.shape[0] // 4, pad.shape[1] // 4
|
||
|
|
small = cv2.resize(pad[: h * 4, : w * 4], (w, h), interpolation=cv2.INTER_AREA)
|
||
|
|
buf = io.BytesIO()
|
||
|
|
im = Image.fromarray((small * 255).astype(np.uint8))
|
||
|
|
if fmt == "PNG-ALPHA": # black ink on transparent background (Springer style)
|
||
|
|
rgba = Image.new("RGBA", im.size, (0, 0, 0, 0))
|
||
|
|
rgba.putalpha(Image.fromarray(255 - np.asarray(im)))
|
||
|
|
rgba.save(buf, "PNG")
|
||
|
|
else:
|
||
|
|
im.save(buf, fmt, **({"quality": 75} if fmt == "JPEG" else {}))
|
||
|
|
return buf.getvalue()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def epub2md_dir(tmp_path: Path) -> Path:
|
||
|
|
"""Minimal epub2md output with two formula images (one inline, one display) and a figure."""
|
||
|
|
root = tmp_path / "buch"
|
||
|
|
(root / "chapters").mkdir(parents=True)
|
||
|
|
(root / "media" / "images").mkdir(parents=True)
|
||
|
|
imgs = {
|
||
|
|
"0001-inline.jpg": synth_image(r"L=\{-\sqrt{2};\sqrt{2}\}", px_per_pt=2.2),
|
||
|
|
"0002-display.jpg": synth_image(r"x_{2,k}=\arcsin\left(-\frac{3}{5}\right)+2k\pi", display=True, px_per_pt=2.2),
|
||
|
|
}
|
||
|
|
for name, data in imgs.items():
|
||
|
|
(root / "media" / "images" / name).write_bytes(data)
|
||
|
|
color = np.zeros((40, 60, 3), np.uint8)
|
||
|
|
color[:, :, 2] = 200
|
||
|
|
Image.fromarray(color).save(root / "media" / "images" / "0003-figure.png")
|
||
|
|
(root / "chapters" / "001-kapitel.md").write_text(
|
||
|
|
"---\nchapter_title: Test\n---\n\n# Kapitel\n\n"
|
||
|
|
"Die Lösungsmenge lautet .\n\n"
|
||
|
|
"Allgemein gilt\n\n\n\n"
|
||
|
|
"```\n\n```\n\n"
|
||
|
|
"\n", encoding="utf-8")
|
||
|
|
report = {"tool": "epub2md", "options": {"math": "auto"}, "input": {"name": "buch.epub", "sha256": "x"},
|
||
|
|
"media": {"files": [{"source": f"OEBPS/{n}", "file": f"media/images/{n}"} for n in imgs]},
|
||
|
|
"warnings": [{"code": "formula-image", "message": "Formel liegt nur als Bild vor (0002-display.jpg)."}]}
|
||
|
|
(root / "conversion-report.json").write_text(json.dumps(report), encoding="utf-8")
|
||
|
|
return root
|