Files
MeowOS-SDK/tuku/test/make_mem_samples.py
T
AskaEth 1725af631b 图库: 门控模型接真缩解后端 + _step 全格式后端(M27)
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。
2026-11-06 11:46:16 +08:00

101 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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())