Files
MeowOS-SDK/sdk/include/meow_ui_image.h
T
AskaEth 11e09af7a4 图库: 修 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)零警告。
2026-11-06 11:46:16 +08:00

98 lines
6.5 KiB
C
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.
/*
* meow_ui_image.h — SDK 图片层(§4,B1)。
*
* 原 meow_ui.h 拆分的一部分(image 模块)。解码后端:M23 真缩解(JPEG DCT 域 / PNG 逐行 /
* BMP 跳行,见 meow_jpeg.h)优先,回退 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/M23)预算解码:解码期受长边约束,返回图最长边 ≤ maxdim,尺寸与
* 「meow_img_load_file + meow_img_downscale(maxdim)」逐字节同口径(公式一致)。
*
* 实现(M23 起):先进真缩解后端(内部 meow_jpeg.c / meow_png_stream.c),解码期只算目标分辨率:
* JPEG:DCT 域缩解(每 8×8 块只解出 N×N 像素,N 由 8·maxdim/长边 取「不欠采样」的最小值;
* N=1..7,N≥8 交回 stb),渐进式跳过精细化扫描、只解各频带首次扫描 —— 低频带已完整,
* 不整幅驻留系数阵列;
* PNG :libz 逐行 inflate + 反滤波,按步长丢行丢列直写目标尺寸(gray/gray+A/RGB/RGBA/
* 调色板/1-16bit,16bit 取高字节,tRNS 透明含 8bit 灰/RGB);
* BMP :按目标行 seek 到源行 + 行内跳列(8bpp 调色板 / 16bpp RGB555 / 24bpp / 32bpp)。
* 峰值只与输出尺寸相关,不随源图分辨率/压缩体积线性增长(2000×3000 页 ≤2.5MB 量级)。
* 不支持的特性(CMYK/YCCK 4 分量 JPEG、算术编码、过订阅 Huffman 表、16bit 量化表、Adam7
* 交错 PNG、RLE/1-4bpp BMP、几乎等尺寸)自动回退 stb 旧路径,对外语义完全不变。
* 小图(长边 ≤ maxdim)走旧路径,与原 API 完全一致;maxdim<=0 等价旧入口。失败返回 NULL。
*
* 尺寸口径说明(M23 评审 P2-2):本入口按「原图 + meow_img_downscale」公式算目标尺寸;M12 旧
* 实现经 stb 的 ceil(w/s) 缩解再精修,源尺寸不是档位整数倍时可能与本入口差 1px(实测 1999×2999:
* 旧 320×480 vs 新 319×480)。阅读器按显示框缩放,无实际影响;PNG/BMP 无此差异。 */
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);
/* 追加(M22)缩解档位选择:取满足「长边/档位 ≥ maxdim」的最大整数档 s ∈ {1,2,4,8},
* 保证缩解结果不欠采样。meow_img_load_file_dim 内部用的就是这个函数;调用方(阅读器)
* 用它枚举候选档位做内存预算,避免两处各写一份而漂移。 */
int meow_img_pick_scale(int longside, int maxdim);
/* 追加(M22)显式档位解码:语义与 meow_img_load_file_dim 相同(结果长边 ≤ maxdim,
* 超了就再精修一次),只是缩解档位由调用方决定。内存吃紧时可以选更粗的档位——输出更小、
* 峰值更低,代价是细节变软。step <= 1 等价长边约束入口;step > 8 按 8 处理。
* M23 起:先走真缩解后端(step 折算成目标长边 ceil(长边/step),后端按该长边选 DCT 阶),
* 峰值只与输出尺寸相关;不支持的特性回退 stb(step 原样传入)。
* M27 起 PNG/BMP 也走同一后端入口(阅读器峰值模型已同步为「目标图 + 工作面」口径);
* 断言与实测见 tuku/test/test_reader_membudget.c 的 B7。 */
meow_img *meow_img_load_file_step(const char *path, int maxdim, int step);
/* 追加(M27):与 meow_img_load_file_step 相同,额外控制回退并回报**实际**路径:
* allow_stb_fallback = 1:后端不支持/失败时回退 stb(与 _step 完全一致);
* allow_stb_fallback = 0:只尝试后端,失败返回 NULL——**绝不**回落 stb。阅读器的门控
* 按「后端峰值」放行时必须用 0,否则头部判定通过、解码中途失败的文件会静默走 stb,
* 实测可放出 18–36MB(截断 12MP JPEG / 头-only BMP / 非法位深 PNG)。失败页由调用方
* 按坏图占位。
* used_backend = 1(M23 后端直出目标尺寸)/ 0(未走成后端)。NULL 时等价 _step(允许回退)。 */
meow_img *meow_img_load_file_step_ex(const char *path, int maxdim, int step,
int allow_stb_fallback, int *used_backend);
/* 追加(M22)精确重采样到 w×h(最近邻,缩小/放大都支持)。阅读器用它把「缩解档位」的
* 结果一次性落到显示框,使命中页仍是单次原生 blit(不做每帧重采样)。同尺寸返回 NULL
* (调用方保留原图);失败返回 NULL。 */
meow_img *meow_img_resample(meow_img *im, int w, int h);
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 */