图库: 修 M27 评审 P1 门控旁路 + 三个 P2(r1)

P1-1:判定为 backend 的页不再无条件放行 + 后端中途失败不再静默回退 stb。
- meow_img_load_file_step_ex 增加 allow_stb_fallback 参数:0 = 只试后端,
  失败返回 NULL(坏图占位),绝不回落 stb。阅读器按 dec.path 传入。
- 旧行为实测:截断 12MP JPEG 18,403kB、3000×3000 24bpp 头-only BMP 36,056kB、
  非法位深 PNG 16,409kB(stb 都"成功"出图)。修复后:
  截断 JPEG 275kB→NULL、头-only BMP 908kB→NULL、非法位深 PNG 门控占位(0 分配)。

P2-1:PNG 支持矩阵补 png_depth_ok 同式(color 2/4/6 仅 8/16;color 3 无 16;
color 0 允许 1/2/4/8/16),不再出现「矩阵说支持、后端拒绝」。
P2-2:后端命中页也保留两道安全阀:MemAvailable<6MB 占位、估算 >12MB 硬上限占位。
P2-3:B8 指标改为「窗口稳定后只 reset 一次」,量整个 30 翻窗口内相对稳态基线的
最大存活增量(淘汰不再掩盖峰值),并打印稳态/驻留/增量。
P2-4:page_source.h 的估算精度口径限定为「后端命中/典型页」。

回归:
- B7c 新增截断 12MP JPEG / 24bpp 头-only BMP / 非法位深 PNG,断言 backend-only
  NULL 且峰值 ≤3MB、或 stb 门控占位;B7 典型页与 B7b 回退矩阵保持全绿。
- test_reader_many_pages 恢复 24bpp 头-only 夹具(1bpp 保留):24bpp 判 failed、
  1bpp 判 skipped;断言 failed=2 / skipped=1。
- run_tests.sh / run_webtoon_tests.sh EXIT=0;sdk/test_meow_img_stream ALL PASS;
  交叉构建(SDK + tuku)零警告。
This commit is contained in:
AskaEth committed 2026-11-06 11:46:16 +08:00
1 parent 1725af631b
commit 11e09af7a4
8 files changed
+171 -49

No files matched your search

+20 -3
View File
@@ -486,6 +486,16 @@ static int mr_png_bits(int color, int depth)
}
}
/* 位深合法性(与 meow_png_stream.c 的 png_depth_ok **逐字同式**,P2-1):
* color 0/3 允许 1/2/4/8(灰度再加 16),color 2/4/6 只允许 8/16。 */
static int mr_png_depth_ok(int color, int depth)
{
if (color == 0) return depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16;
if (color == 3) return depth == 1 || depth == 2 || depth == 4 || depth == 8;
if (color == 2 || color == 4 || color == 6) return depth == 8 || depth == 16;
return 0;
}
/* 后端支持矩阵(镜像 meow_jpeg.c / meow_png_stream.c 的拒绝条件;字段未知一律不支持)。
* eff 是后端实际会收到的 maxdim(见 mr_effective_dim)。 */
static int mr_backend_supported(const mr_img_info *in, int eff)
@@ -511,7 +521,7 @@ static int mr_backend_supported(const mr_img_info *in, int eff)
case MR_IMG_CODEC_PNG: {
if (in->interlace || in->compression || in->filter) return 0;
if (in->w > 65535 || in->h > 65535) return 0;
if (mr_png_bits(in->color, in->depth) == 0) return 0;
if (!mr_png_depth_ok(in->color, in->depth)) return 0;
return 1;
}
case MR_IMG_CODEC_BMP:
@@ -648,12 +658,19 @@ void reader_estimate_peak(const mr_img_info *in, int step, int box_w, int box_h,
int longside = in->w > in->h ? in->w : in->h;
int eff = mr_effective_dim(longside, step, dim);
/* 1) 先看后端能否接住:命中 → 直接放行(后端峰值与源尺寸无关,不需要门控)。 */
/* 1) 先看后端能否接住:命中时峰值与源尺寸无关(典型页 <2.6MB),不做 3MB 常态门控;
* 但仍保留两道安全阀(P2-2):MemAvailable <6MB 直接占位、估算超过 12MB 硬上限占位。
* 后端路由由 reader 用 backend-only 入口执行(P1-1),失败即坏图,绝不回落 stb。 */
if (mr_backend_supported(in, eff)) {
out->path = MR_DECODE_PATH_BACKEND;
out->peak_bytes = mr_backend_peak_bytes(in, eff, step, box_w, box_h,
&out->tw, &out->th);
out->skip = MR_DECODE_OK;
if (memavail_kb >= 0 && memavail_kb < MR_MEM_FLOOR_KB)
out->skip = MR_DECODE_SKIP_LOWMEM;
else if (out->peak_bytes > MR_PEAK_HARD_BYTES)
out->skip = MR_DECODE_SKIP_PEAK;
else
out->skip = MR_DECODE_OK;
return;
}
+2 -1
View File
@@ -140,7 +140,8 @@ int mr_probe_info_mem(const void *buf, size_t len, mr_img_info *info);
*
* 参数:step 与 meow_img_load_file_step 同义(JPEG 档位提示);box_w/box_h 是阅读器
* 最终显示框;memfree_kb/memavail_kb 读不到时传 -1。out 必须非 NULL。
* 估算口径保证 ≥ 实测(--wrap malloc)且不超过实测 1.5×(见 tuku/test 断言)。 */
* 估算精度口径:**后端命中页 / 典型页**保证估算 ≥ 实测(--wrap malloc)且 ≤1.5×;
* 回退 stb 的小图只保证门控安全(可能保守,不强求 1.5× 上界)。断言见 tuku/test。 */
#define MR_DECODE_PATH_STB 0
#define MR_DECODE_PATH_BACKEND 1