fix(sdk): 收编公开 SDK 仓独有改进(图片预算解码 + JPEG 解码期缩解),主仓成为唯一权威源

公开仓 ~/Proj/MeowOS-SDK 的 sdk/ 与主仓 patch_v2/sdk 无共同 git 历史(subtree split
重写了提交哈希,不做跨仓 merge/subtree pull),按内容逐文件裁决。公开仓侧的真增量只有
commit 21bffa1(图片预算解码)及其依赖;其余差异是公开仓的自包含打包(扁平 include/、
vendored 头与 meow_font.c)或主仓早已超越的旧快照。

一、取公开侧(纯追加,主仓该文件无独有改动)
- stb_image.h:新增 stbi_load_scaled / stbi_load_scaled_from_memory——JPEG 输出级按
  步长抽取行/列,整幅原尺寸输出缓冲从不物化;进升级 JPEG 各分量系数 IDCT 进像素平面后
  立即释放。scale<=1 与旧 API 等价,非 JPEG 忽略。主仓版本的 diff 全部是公开侧新增
  (无主仓独有 hunk),故整体替换。
- meow_ui_img.c:追加 img_pick_scale / img_finish_dim / meow_img_probe_file /
  meow_img_load_file_dim / meow_img_load_mem_dim。既有加载入口一字未改。
- include/meow_ui_image.h:追加上述三个公共声明。
- 新增 test_meow_img_budget.c + test_meow_img_budget_gen.py(--wrap malloc/free 打点
  统计瞬时峰值,B1-B9 覆盖矩阵)。

二、取主仓(公开侧为旧快照或自包含适配,并入会回退功能)
- meow_ui_ime.c / test_ime_fix.c:主仓 bug3 修复(IME 打开瞬间 200ms TAP 冷却窗 +
  drain/40ms/再 drain)及其回归用例为公开侧所无;公开侧同名文件不含该修复。
- meow_ui_input.c / meow_ui_internal.h:主仓 meow_input_touch_reset(drain 与叠加抑制
  进入沿共用)、FreeType 渲染/字形声明、meow_time_ms_from_parts。公开侧此三处无独有声明
  可并,取主仓即并集。
- meow_ui_gfx.c / meow_ui_sys.c / meow_cachegov.c:主仓时钟 ABI 根因修复(o32 time32,
  meow_ui_time.c 链接期接管 __clock_gettime*)已把这些文件的本地 now_ms 统一为
  meow_ui_time_ms();公开侧仍是各自 clock_gettime,回落即回退根因修复。
- meow_ui_dialog.c / meow_select.c:主仓 MD3 后续(对话框按钮胶囊 MEOW_SHAPE_FULL、
  bottom sheet 顶角 28)晚于公开侧快照,公开侧等于旧版。
- include/meow_ui_font.h:主仓多出 FreeType 段与 stdint 自洽 include,公开侧缺。
- build_sdk.sh / build_sdk_host.sh:主仓含 FreeType vendor 裁剪构建、meow_ui_time TU、
  launcher meow_font.a 打包;公开侧为自包含重写,不回流。
- 其余 test_*.c:差异仅为编译配方注释(公开仓用 -Iinclude、无 meow_ui_time.c、标注
  「需主仓组件故公开仓跳过」等),对主仓目录布局不成立,不改。

三、不引入(vendored 副本 / 打包产物)
- meow_font.c、include/meow_font.h、include/meow_ipc.h、include/meow_notif.h:公开仓
  为自包含 vendored 副本(meow_font.c 与主仓 font/meow_font.c 逐字节相同),主仓已有
  权威源,复制会制造双源。

裁决说明(两边都改过的文件):
- test_meow_ui_select.c:公开仓把 T1 探针从 x=10 改到 x=12(commit 432875d)。主仓 x=10
  在本树实测 6/6 PASS(容器卡左缘 8、文本左缘 24,x=10 已在卡内且避开圆角),无失败
  可修,故不跟进该改动,避免无谓 churn。
- 公开侧「meow_media_playctl」一类 API 名:仅出现在公开仓 vendored 头/文档,主仓
  sdk 无对应实现,未硬造。

四、验证(worktree / 分支 feat/sdk-absorb-public-deltas)
- build_sdk_host.sh --verify:0 warning / 0 error;成员清单 76 个(OBJS 32 +
  meow_font.o + freetype 43)一致,全部 ELF32 MIPS32 rel2 (o32)。
- nm 确认 meow_ui.a 导出 meow_img_probe_file / meow_img_load_file_dim /
  meow_img_load_mem_dim / stbi_load_scaled / stbi_load_scaled_from_memory。
- 宿主测试:对「未改动的 main SDK」跑同一套矩阵做基线对比,40 项同名结果逐项完全一致
  (22 PASS / 11 FAIL / 7 建链失败,失败项与失败计数一字不差);本提交新增
  test_meow_img_budget 为 PASS。补充按各测试正确配方单编:test_meow_img_color、
  test_meow_lyric、test_meow_lyric_view、test_meow_ui_ft(显式传入 MiSans 字体)、
  test_umbrella 均通过/0 warning。
- 既有失败全部是 Termux 环境问题,与本次合并无关(基线同样失败):/tmp 不可写导致
  mkdtemp/fopen/bind EACCES(config/vol/notif_open/notify_ipc/notify_integration/
  sb_collapse/overlay_suppress/input_keys),audiod 守护不在场(ui_audio_host),
  test_sdk_fixes 阻塞循环超时(基线同样 124)。
- hello_app 用新 meow_ui.a 重链成功(0 warning,静态 MIPS32r2),可执行文件
  471380→473636 字节(+2256,新解码路径)。

五、影响
meow_ui.a 内容变化(新增 4 个 MEOW_API + stb 解码路径改变)→ 需重编重链 hello / files /
reader / ncm 四 App 与 meow_launcherd。
This commit is contained in:
AskaEth committed 2026-11-05 20:03:20 +08:00
1 parent 4e60f440f6
commit e23bdca26a
5 files changed
+684 -12

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""test_meow_img_budget_gen.py — 为宿主测试 test_meow_img_budget.c 生成图片夹具。
用法:python3 test_meow_img_budget_gen.py <输出目录>
依赖:Pillow(PIL)。夹具只含结构化图案(白底/黑线/灰块),体积极小。
生成:
big.jpg 3200x2600 baseline 4:2:0 JPEG(8.32MP,峰值对比主用例)
bigprog.jpg 3200x2600 progressive JPEG(验证进升级解码走同一缩解路径)
page.jpg 1600x2400 baseline JPEG(finding 里 15.4MB 的漫画页原尺寸)
small.jpg 64x64 baseline JPEG(「小图不动」用例)
big.png 2400x1600 RGB PNG(stb 无解码期缩放:峰值如实记录,不作改善断言)
big.bmp 2400x1600 24bpp BMP(同上)
broken.jpg JPEG 魔数 + 垃圾字节(头部解析失败,坏图用例)
"""
import os
import sys
from PIL import Image, ImageDraw
def page_pattern(w, h):
"""漫画页近似:白底 + 分镜框线 + 灰阶网点带。内容稀疏 → JPEG 体积小。"""
im = Image.new("RGB", (w, h), (250, 249, 245))
d = ImageDraw.Draw(im)
for k in range(0, min(w, h) - 400, 60):
d.rectangle([100 + k, 100 + k, 400 + k, 300 + k], outline=(12, 12, 14), width=5)
for band in range(14):
y0 = band * h // 14
for x in range(0, w, 9):
d.line([(x, y0), (x + 4, y0 + 7)], fill=(110, 110, 116))
return im
def main():
if len(sys.argv) != 2:
print(__doc__)
return 2
out = sys.argv[1]
os.makedirs(out, exist_ok=True)
big = page_pattern(3200, 2600)
big.save(os.path.join(out, "big.jpg"), "JPEG", quality=55, subsampling=2)
big.save(os.path.join(out, "bigprog.jpg"), "JPEG", quality=55, subsampling=2,
progressive=True)
small = page_pattern(64, 64)
small.save(os.path.join(out, "small.jpg"), "JPEG", quality=80, subsampling=2)
page = page_pattern(1600, 2400)
page.save(os.path.join(out, "page.jpg"), "JPEG", quality=55, subsampling=2)
mid = page_pattern(2400, 1600)
mid.save(os.path.join(out, "big.png"), "PNG")
mid.save(os.path.join(out, "big.bmp"), "BMP")
# 坏图:JPEG 魔数 + 垃圾字节 → 头部解析失败(stb 对「截断但头部完整」很宽容,不能只截断)
garbage = bytes((i * 37 + 11) & 0xFF for i in range(256))
with open(os.path.join(out, "broken.jpg"), "wb") as f:
f.write(b"\xff\xd8\xff\xe0" + garbage)
for name in ("big.jpg", "bigprog.jpg", "page.jpg", "small.jpg", "big.png",
"big.bmp", "broken.jpg"):
print(" %-12s %8d B" % (name, os.path.getsize(os.path.join(out, name))))
return 0
if __name__ == "__main__":
sys.exit(main())