M23 交付了真缩解后端却「修好了用不上」:_step 只接 JPEG,而阅读器的峰值模型
仍是 stb 口径(PNG/BMP 按 W·H·4、JPEG 按缩解后整幅 RGBA),12MP/PNG 页全被判
超预算占位。本次把两处缝焊上:
- sdk/meow_ui_img.c:meow_img_load_file_step 的 JPEG-only 限制放开到 PNG/BMP;
新增 meow_img_load_file_step_ex 回报实际路径(backend/stb),日志可核对预判。
- tuku/logic/reader/page_source.[ch]:新增 reader_estimate_peak(),成为峰值模型 +
预算 + MemAvailable 门控的唯一实现(reader 不再另写一份)。
* 后端命中(JPEG SOF0/1/2、≤3 分量、8bit、N=1..7;PNG 非交错/标准压缩/合法色型;
BMP DIB≥40/BI_RGB/8·16·24·32bpp)→ 峰值 = 目标图 + 分量平面/行缓冲 + 固定开销,
与源分辨率无关 → 直接放行,不门控;
* 只有回退 stb(CMYK/算术编码、Adam7、RLE/1-4bpp、N≥8 小图等)才按 M22 stb 模型
算峰值,超 3MB 或 MemAvailable <6MB 才占位。Adam7 另补 stb 的整幅暂存上界。
- reader:删掉本地 stb 模型/常量,统一调 reader_estimate_peak;日志加 path=backend|stb。
- 测试:6 类典型页(2000×3000 baseline/渐进/restart、1600×2400 PNG/BMP、4MP、12MP)
断言全部 backend + 不占位 + 估算 ≥ 实测且 ≤1.5×(实测 1.03–1.08×);两条路径输出
尺寸逐像素一致;CMYK/Adam7/1bpp 断言走 stb 并按旧门控占位;连翻 30 页无占位、
单页分配峰值 ≤3MB;membudget 链接补 meow_ui_time.c 与 M23 两个解码 TU。
101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
||
"""make_mem_samples.py — 为 test_reader_membudget.c 生成解码夹具(M22 / M27)。
|
||
|
||
用法:python3 make_mem_samples.py <输出目录>
|
||
依赖:Pillow。没有 Pillow 时测试自动 SKIP JPEG 相关断言(BMP/PNG 小夹具由 C 直接写)。
|
||
|
||
M27 追加「6 类典型页」与「回退路径」夹具,用来断言门控模型与真缩解后端同口径:
|
||
典型(应全部走后端、不占位):
|
||
base2000.jpg 2000x3000 baseline
|
||
prog2000.jpg 2000x3000 progressive
|
||
restart2000.jpg 2000x3000 progressive + restart markers
|
||
page1600.png 1600x2400 PNG
|
||
page1600.bmp 1600x2400 BMP
|
||
mp4.jpg 2320x1740(4MP)
|
||
mp12.jpg 4000x3000(12MP)
|
||
回退(后端拒绝、按旧 stb 门控占位):
|
||
cmyk.jpg 2000x3000 CMYK(4 分量)
|
||
adam7.png 1600x2400 Adam7 交错
|
||
mono1.bmp 1600x2400 1bpp
|
||
M22 旧断言仍用:
|
||
page.jpg / big4.jpg / prog.jpg(1000x1500 / 2000x2000 / 1000x1500 progressive)
|
||
"""
|
||
import os
|
||
import struct
|
||
import sys
|
||
import zlib
|
||
|
||
from PIL import Image, ImageDraw
|
||
|
||
|
||
def pattern(w, h, mode="RGB"):
|
||
im = Image.new(mode, (w, h), (248, 247, 244) if mode == "RGB" else 200)
|
||
d = ImageDraw.Draw(im)
|
||
for k in range(0, min(w, h) - 200, 70):
|
||
d.rectangle([20 + k, 20 + k, 160 + k, 120 + k], outline=(10, 10, 12), width=3)
|
||
return im
|
||
|
||
|
||
def chunk(tag, data):
|
||
return (struct.pack(">I", len(data)) + tag + data +
|
||
struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF))
|
||
|
||
|
||
def write_adam7(path, img):
|
||
"""手写 Adam7 交错 PNG(Pillow 不支持写交错)。RGB8。"""
|
||
w, h = img.size
|
||
px = img.load()
|
||
raw = bytearray()
|
||
passes = [(0, 0, 8, 8), (4, 0, 8, 8), (0, 4, 4, 8), (2, 0, 4, 4),
|
||
(0, 2, 2, 4), (1, 0, 2, 2), (0, 1, 1, 2)]
|
||
for (x0, y0, dx, dy) in passes:
|
||
xs = list(range(x0, w, dx))
|
||
ys = list(range(y0, h, dy))
|
||
if not xs or not ys:
|
||
continue
|
||
for y in ys:
|
||
raw.append(0)
|
||
for x in xs:
|
||
r, g, b = px[x, y][:3]
|
||
raw += bytes((r, g, b))
|
||
ihdr = struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 1)
|
||
data = (b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) +
|
||
chunk(b"IDAT", zlib.compress(bytes(raw))) + chunk(b"IEND", b""))
|
||
with open(path, "wb") as f:
|
||
f.write(data)
|
||
|
||
|
||
def main():
|
||
if len(sys.argv) != 2:
|
||
print(__doc__)
|
||
return 2
|
||
out = sys.argv[1]
|
||
os.makedirs(out, exist_ok=True)
|
||
|
||
# ---- M22 旧断言夹具 ----
|
||
pattern(1000, 1500).save(os.path.join(out, "page.jpg"), "JPEG", quality=60, subsampling=2)
|
||
pattern(2000, 2000).save(os.path.join(out, "big4.jpg"), "JPEG", quality=60, subsampling=2)
|
||
pattern(1000, 1500).save(os.path.join(out, "prog.jpg"), "JPEG", quality=60, subsampling=2,
|
||
progressive=True)
|
||
|
||
# ---- M27 6 类典型页 ----
|
||
big = pattern(2000, 3000)
|
||
big.save(os.path.join(out, "base2000.jpg"), "JPEG", quality=60, subsampling=2)
|
||
big.save(os.path.join(out, "prog2000.jpg"), "JPEG", quality=60, subsampling=2, progressive=True)
|
||
big.save(os.path.join(out, "restart2000.jpg"), "JPEG", quality=60, subsampling=2,
|
||
progressive=True, restart_marker_blocks=8)
|
||
pattern(1600, 2400).save(os.path.join(out, "page1600.png"), "PNG")
|
||
pattern(1600, 2400).save(os.path.join(out, "page1600.bmp"), "BMP")
|
||
pattern(2320, 1740).save(os.path.join(out, "mp4.jpg"), "JPEG", quality=60, subsampling=2)
|
||
pattern(4000, 3000).save(os.path.join(out, "mp12.jpg"), "JPEG", quality=60, subsampling=2)
|
||
|
||
# ---- M27 回退路径 ----
|
||
big.convert("CMYK").save(os.path.join(out, "cmyk.jpg"), "JPEG", quality=60)
|
||
write_adam7(os.path.join(out, "adam7.png"), pattern(1600, 2400))
|
||
pattern(1600, 2400).convert("1").save(os.path.join(out, "mono1.bmp"), "BMP")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|