89 lines
3.3 KiB
Python
89 lines
3.3 KiB
Python
"""Chunking tests — 2D tiling keeps every chunk within the render width.
|
|
|
|
The embedder skips any chunk wider than the render width (875px), so the chunker
|
|
must split wide tiles (PDFs, landscape pages) along the width as well as the
|
|
height. Narrow web tiles (<= viewport_width) must keep their old single-column
|
|
height-strip layout unchanged so existing indexes stay reproducible.
|
|
"""
|
|
|
|
import json
|
|
|
|
from PIL import Image
|
|
|
|
from pixelrag_embed.chunk import CHUNK_HEIGHT, chunk_article
|
|
|
|
|
|
def _make_tile(dir_path, w, h, viewport_width=None):
|
|
dir_path.mkdir(parents=True, exist_ok=True)
|
|
Image.new("RGB", (w, h), (255, 255, 255)).save(dir_path / "tile_0000.png")
|
|
meta = {"tiles": ["tile_0000.png"], "tile_height": 8192}
|
|
if viewport_width is not None:
|
|
meta["viewport_width"] = viewport_width
|
|
(dir_path / "tiles.json").write_text(json.dumps(meta))
|
|
return dir_path
|
|
|
|
|
|
def _chunks(dir_path):
|
|
return json.loads((dir_path / "chunks.json").read_text())["chunks"]
|
|
|
|
|
|
def test_narrow_tile_unchanged(tmp_path):
|
|
# 875-wide tall web tile: single-column height strips, exactly as before.
|
|
d = _make_tile(tmp_path / "a.png.tiles", 875, 3000)
|
|
chunk_article(str(d))
|
|
cs = _chunks(d)
|
|
assert [c["file"] for c in cs] == [
|
|
"chunk_0000_00.png",
|
|
"chunk_0000_01.png",
|
|
"chunk_0000_02.png",
|
|
]
|
|
assert [c["y_offset"] for c in cs] == [0, CHUNK_HEIGHT, 2 * CHUNK_HEIGHT]
|
|
assert all(c["x_offset"] == 0 and c["width"] == 875 for c in cs)
|
|
|
|
|
|
def test_short_narrow_tile_copied_whole(tmp_path):
|
|
# <= viewport_width and <= CHUNK_HEIGHT: one chunk, tile copied verbatim.
|
|
d = _make_tile(tmp_path / "a.png.tiles", 600, 500)
|
|
chunk_article(str(d))
|
|
cs = _chunks(d)
|
|
assert len(cs) == 1
|
|
assert cs[0]["file"] == "chunk_0000_00.png"
|
|
assert cs[0]["width"] == 600 and cs[0]["height"] == 500
|
|
|
|
|
|
def test_wide_tile_split_into_columns(tmp_path):
|
|
# Letter PDF at 200 DPI (~1700x2200): 2 columns x 3 rows, all <= 875 wide.
|
|
d = _make_tile(tmp_path / "a.png.tiles", 1700, 2200)
|
|
chunk_article(str(d))
|
|
cs = _chunks(d)
|
|
assert len(cs) == 6
|
|
assert all(c["width"] <= 875 for c in cs)
|
|
# every produced chunk file is on disk at its recorded size
|
|
for c in cs:
|
|
img = Image.open(d / c["file"])
|
|
assert img.size == (c["width"], c["height"])
|
|
# columns are full viewport_width (875) with the remainder last, covering
|
|
# the full width with no gaps
|
|
row0 = sorted((c for c in cs if c["y_offset"] == 0), key=lambda c: c["x_offset"])
|
|
assert [c["width"] for c in row0] == [875, 825]
|
|
assert row0[0]["x_offset"] == 0
|
|
assert row0[-1]["x_offset"] + row0[-1]["width"] == 1700
|
|
|
|
|
|
def test_very_wide_tile_never_exceeds_width(tmp_path):
|
|
# 19-inch landscape figure (3800px): many columns, still all <= 875, no skips.
|
|
d = _make_tile(tmp_path / "a.png.tiles", 3800, 2200)
|
|
chunk_article(str(d))
|
|
cs = _chunks(d)
|
|
assert cs, "wide tile must still produce chunks (not be skipped)"
|
|
assert max(c["width"] for c in cs) <= 875
|
|
|
|
|
|
def test_short_wide_tile_splits_width(tmp_path):
|
|
# Short but wide (was copied whole -> too wide -> skipped). Now splits width.
|
|
d = _make_tile(tmp_path / "a.png.tiles", 1700, 500)
|
|
chunk_article(str(d))
|
|
cs = _chunks(d)
|
|
assert len(cs) == 2
|
|
assert all(c["width"] <= 875 and c["height"] == 500 for c in cs)
|