sdk: 图片层追加预算解码入口,JPEG 解码期缩解(峰值 43.7→14.0 MiB)
M6 finding(vuln/high):meow_img_load_file 必先整幅 RGBA 解码,1600×2400 漫画页 瞬时峰值 20.2 MiB(15.4 MiB 输出 + 5.5 MiB YCbCr 平面),超设备 ~14MB 口径, App 侧无法规避。 调研(vendored stb v2.30):无解码期缩放能力——JPEG 走固定 hs/vs 重采样到全尺寸, PNG 一次性 inflate 整幅 raw_image,公共 API 只有 load/load_16/loadf/info。 完整缩小 IDCT 需改编 1/2、1/4、1/8 IDCT + 进升级系数存储 + MCU 尺寸,改动面大且 易出静默像素错误,故不重写解码器。 改为受控的最小追加(sdk/stb_image.h): - 新增 stbi_load_scaled / stbi_load_scaled_from_memory:JPEG 输出级按步长 s 抽取 行/列(resample 状态机逐行推进,仅采样行做颜色转换),整幅原尺寸输出缓冲从不 物化;scale<=1 与旧 API 逐字节等价,非 JPEG 忽略。 - 进升级 JPEG:各分量系数 IDCT 进像素平面后立即释放(原来拖到输出分配之后)。 - 旧公共 API 行为不变。 SDK 追加式入口(旧 API 一字未改): - meow_img_load_file_dim / meow_img_load_mem_dim(path/buf, maxdim):stbi_info 头探测 选 1/2、1/4、1/8 整数档(取「长边/s ≥ maxdim」最大档,不欠采样),再交既有 meow_img_downscale 精修;小图/maxdim<=0 走旧路径。 - meow_img_probe_file:只读头取尺寸,供 App 在 OOM 前提示。 实测(宿主 test_meow_img_budget,--wrap malloc 打点,全部 PASS): 8.32MP JPEG 43.70 → 13.96 MiB(新/旧 0.32) 1600×2400 页 20.16 → 9.18 MiB progressive 43.70 → 35.83 MiB(系数阵列扫描期驻留,残余上限) PNG 2400×1600 25.65 → 25.65 MiB(stb 无 PNG 缩解,如实记录) BMP 2400×1600 14.65 → 15.23 MiB(同上,多一次降采样小缓冲) 缩解结果与「整幅解码+downscale」网格平均差 6.28;对 PIL 逐像素比对与全幅解码 同误差量级(mean ≤0.02, max ≤3)。 验证:build_sdk.sh 重编 meow_ui.a 0 warning;examples/hello 重链 0 warning; tuku 用 MEOW_SDK_DIR 指向本分支 sdk 重链 0 warning;既有 test_meow_img_color 仍全 PASS。
This commit is contained in:
1 parent
5f40d6fd87
commit
21bffa1aeb
5 files changed
+684
-12
No files matched your search
@@ -42,6 +42,65 @@ meow_img *meow_img_load_file(const char *path)
|
||||
return img_alloc(w, h, p);
|
||||
}
|
||||
|
||||
/* 追加(M12):预算解码。选整数缩解档位 s ∈ {1,2,4,8}——取满足「长边/s ≥ maxdim」的最大档,
|
||||
* 保证缩解结果不欠采样(不丢细节),再由 meow_img_downscale 精修到 maxdim。长边 < 2*maxdim
|
||||
* 时无档可用(s=1),退回整幅解码后精修——此时本就接近目标尺寸,无需牺牲。 */
|
||||
static int img_pick_scale(int longside, int maxdim)
|
||||
{
|
||||
int s = 1;
|
||||
while (s < 8 && (longside / (s * 2)) >= maxdim) s *= 2;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* 追加(M12):缩解结果落地 + 需要时精修。p 所有权转交。 */
|
||||
static meow_img *img_finish_dim(unsigned char *p, int w, int h, int maxdim)
|
||||
{
|
||||
if (!p) return NULL;
|
||||
meow_img *im = img_alloc(w, h, p);
|
||||
if (!im) return NULL;
|
||||
if (im->w <= maxdim && im->h <= maxdim) return im;
|
||||
meow_img *small = meow_img_downscale(im, maxdim);
|
||||
if (!small) return im; /* 精修失败:缩解结果已小于原图,仍可用 */
|
||||
meow_img_free(im);
|
||||
return small;
|
||||
}
|
||||
|
||||
int meow_img_probe_file(const char *path, int *w, int *h, int *channels)
|
||||
{
|
||||
int pw = 0, ph = 0, pc = 0;
|
||||
if (!path || !stbi_info(path, &pw, &ph, &pc)) return 0;
|
||||
if (w) *w = pw;
|
||||
if (h) *h = ph;
|
||||
if (channels) *channels = pc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
meow_img *meow_img_load_file_dim(const char *path, int maxdim)
|
||||
{
|
||||
if (!path) return NULL;
|
||||
if (maxdim <= 0) return meow_img_load_file(path); /* 不限尺寸 = 旧入口 */
|
||||
int w = 0, h = 0, c = 0;
|
||||
if (!stbi_info(path, &w, &h, &c)) return NULL;
|
||||
int longside = w > h ? w : h;
|
||||
if (longside <= maxdim) return meow_img_load_file(path); /* 小图不动:旧路径 */
|
||||
unsigned char *p = stbi_load_scaled(path, &w, &h, &c, 4, img_pick_scale(longside, maxdim));
|
||||
return img_finish_dim(p, w, h, maxdim);
|
||||
}
|
||||
|
||||
meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim)
|
||||
{
|
||||
if (!buf || len <= 0) return NULL;
|
||||
if (maxdim <= 0) return meow_img_load_mem(buf, len);
|
||||
int w = 0, h = 0, c = 0;
|
||||
if (!stbi_info_from_memory((const unsigned char *)buf, len, &w, &h, &c)) return NULL;
|
||||
int longside = w > h ? w : h;
|
||||
if (longside <= maxdim) return meow_img_load_mem(buf, len);
|
||||
unsigned char *p = stbi_load_scaled_from_memory((const unsigned char *)buf, len,
|
||||
&w, &h, &c, 4,
|
||||
img_pick_scale(longside, maxdim));
|
||||
return img_finish_dim(p, w, h, maxdim);
|
||||
}
|
||||
|
||||
void meow_img_free(meow_img *im)
|
||||
{
|
||||
if (!im) return;
|
||||
|
||||
Reference in new issue
Block a user