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。
55 lines
2.8 KiB
C
55 lines
2.8 KiB
C
/*
|
||
* meow_ui_image.h — SDK 图片层(§4,B1)。
|
||
*
|
||
* 原 meow_ui.h 拆分的一部分(image 模块)。内部 stb_image(单头文件,静态编入 meow_ui.a)
|
||
* 解 PNG/JPEG/BMP,统一转 RGBA。meow_img 为不透明句柄(前向声明见 meow_ui_types.h)。
|
||
*/
|
||
#ifndef MEOW_UI_IMAGE_H
|
||
#define MEOW_UI_IMAGE_H
|
||
|
||
#include "meow_ui_types.h"
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/* ============================================================ */
|
||
/* §4 图片层 */
|
||
/* ============================================================ */
|
||
typedef struct meow_img meow_img; /* 句柄,由 meow_img_* 管理,不透明 */
|
||
|
||
meow_img *meow_img_load_file(const char *path); /* 内部读文件 + stb 解码 */
|
||
meow_img *meow_img_load_mem(const void *buf, int len);
|
||
void meow_img_free(meow_img *img);
|
||
|
||
/* 追加(M12)预算解码:只读文件头取原始尺寸,不解码像素(零像素内存)。成功 1,失败 0。
|
||
* App 可用它在加载前判断「图太大」并给用户提示,而不必先撞 OOM。 */
|
||
int meow_img_probe_file(const char *path, int *w, int *h, int *channels);
|
||
|
||
/* 追加(M12)预算解码:解码期受长边约束,返回图最长边 ≤ maxdim。
|
||
* JPEG:按 1/2、1/4、1/8 整数步长抽取解码(stbi_load_scaled),整幅原尺寸 RGBA 缓冲从不物化,
|
||
* 峰值 ≈ 亮度分量平面 + 缩解输出 + 单行缓冲;随后用 meow_img_downscale 精修到 maxdim。
|
||
* PNG/BMP 等 stb 无解码期缩放能力的格式:整幅解码后立即降采样(峰值同旧入口,见 M12 报告)。
|
||
* 小图(长边 ≤ maxdim)走旧路径,与原 API 完全一致;maxdim<=0 等价旧入口。失败返回 NULL。 */
|
||
meow_img *meow_img_load_file_dim(const char *path, int maxdim);
|
||
meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim);
|
||
|
||
int meow_img_w(const meow_img *img);
|
||
int meow_img_h(const meow_img *img);
|
||
/* 访问器:取 RGBA 像素指针(4 通道 straight alpha;供取色/直读像素)。meow_img 对外 opaque,
|
||
* 本函数为其唯一像素读入口;NULL 返回 NULL。 */
|
||
const unsigned char *meow_img_pixels(const meow_img *img);
|
||
|
||
void meow_ui_img(int x, int y, meow_img *img); /* 原始尺寸 */
|
||
/* 内存瘦身:最近邻等比缩放到最长边 ≤maxdim,返回新图;原图已 ≤maxdim 返回 NULL。
|
||
* 调用方负责 free 旧图与返回值(若返回)。封面/背景大图驻留内存瘦身用。 */
|
||
meow_img *meow_img_downscale(meow_img *img, int maxdim);
|
||
void meow_ui_img_scaled(int x, int y, int w, int h, meow_img *img); /* 最近邻缩放 */
|
||
void meow_ui_img_alpha(int x, int y, int w, int h, meow_img *img, int alpha);
|
||
void meow_ui_img_cover(int x, int y, int size, meow_img *img); /* 居中裁方 → size×size */
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* MEOW_UI_IMAGE_H */
|