feat(sdk): M26 公开仓真缩解图像栈并入主仓 — JPEG DCT/PNG 逐行/BMP 跳行后端 + RGB565 页图
主仓 SDK 的图片层原本是 220 行 stb 直通(整幅解码后重采样)。公开仓 MeowOS-SDK 的同一子系统已被真实 App(tuku 阅读器)驱动并做过峰值实测与像素比对,故以公开仓 为权威方向并入主仓 meow_ui.a,两个方向的新功能都保留(逐文件 diff 确认公开仓是 严格超集:无一处「双方互有增减」)。 - 新增 meow_jpeg.c / meow_jpeg.h:DCT 域缩解 1/8、1/4、1/2(N=1/2/4 点 IDCT), 渐进式只解到首个精细化扫描;不支持项(CMYK/YCCK、算术编码、过订阅 DHT、16bit 量化表)返回 0 由调用方回退 stb - 新增 meow_png_stream.c:libz 逐行 inflate + 反滤波,按步长丢行丢列直写目标尺寸; BMP 按目标行 seek + 行内跳列(8/16/24/32bpp) - meow_ui_img.c + include/meow_ui_image.h:新增 meow_img_pick_scale / load_file_step / load_file_step_ex / resample 四个公开入口;_dim 与 _mem_dim 先进后端,失败/不支持才回退 stb(对外语义不变) - include/meow_ui_draw.h + meow_ui_gfx.c:M32 RGB565 页图 5 函数 (meow_gfx_rgb565 / rgba_to_rgb565 / blit_rgb565 / _scaled)。gfx 保留主仓的 `#include "../meow_launcherd/meow_font.h"` 与 <time.h>(公开仓自 vendored meow_font.h 且无 <time.h>,机械覆盖会丢这两行) - meow_jpeg.h 保持内部:不进 meow_ui.h 伞头,include/ 下无任何头暴露 meow_jpeg_* - build_sdk.sh:OBJS 插入 meow_jpeg / meow_png_stream(32→34);成员数 76→78(+meow_font.o +43 freetype),--verify 全为 ELF32 MIPS32 rel2/o32 - 测试:新增 test_meow_img_stream.c(S1-S16),test_meow_img_budget.c 同步公开仓 版(B9 断言收紧为 p_new <= p_old);22 个既有宿主测试的编译注释行补 meow_jpeg.c / meow_png_stream.c / -lz(meow_ui_img.c 现引用后端符号,不加即 undefined reference) 宿主实测:S1-S16 全绿(S7 与 stb 网格像素一致:JPEG mad 4.35-13.69、PNG/BMP mad 0.00;S9 回退矩阵 CMYK/1bpp BMP/Adam7 均拒绝且 stb 仍成功),B1-B9 全绿 (B9 PNG 峰值 25.65→0.61 MiB、BMP 14.65→0.59 MiB)。回归 test_meow_ui_widgets / scroll / ime_fix / test_umbrella 全过。zlib 在应用链接期解析:meow_ui.a 只留 inflate* 未定义符号,四个 App 构建脚本原本就带 $SYSROOT/lib/libz.a,静态 linkcheck(meow_ui.a + libz.a -lpthread)通过。 注:主仓 patch_v2/reader_app 仍自带 vendored stb、不用 meow_img_*,本单不改变 阅读器的内存占用;RGB565 页图接入 reader_app 是另一个任务。
This commit is contained in:
1 parent
479d93a3bf
commit
ee5796747d
32 files changed
+3049
-64
No files matched your search
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* meow_ui_img.c — 图片层(B1.2)。基于 stb_image(单头文件、静态编入),
|
||||
* 解 PNG/JPEG/BMP → RGBA,统一最近邻缩放/居中裁方。
|
||||
* meow_ui_img.c — 图片层(B1.2)。解码:M23 真缩解后端(meow_jpeg.c / meow_png_stream.c)
|
||||
* 优先,不支持/失败回退 stb_image(单头文件、静态编入);统一输出 RGBA,最近邻缩放/居中裁方。
|
||||
*/
|
||||
#include "meow_ui.h"
|
||||
#include "meow_ui_internal.h"
|
||||
#include "stb_image.h"
|
||||
#include "meow_jpeg.h" /* M23 真缩解后端(内部头,不对外导出) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -45,7 +46,7 @@ meow_img *meow_img_load_file(const char *path)
|
||||
/* 追加(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 meow_img_pick_scale(int longside, int maxdim)
|
||||
{
|
||||
int s = 1;
|
||||
while (s < 8 && (longside / (s * 2)) >= maxdim) s *= 2;
|
||||
@@ -79,25 +80,107 @@ 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); /* 不限尺寸 = 旧入口 */
|
||||
/* 追加(M23):真缩解后端直接产出目标尺寸(JPEG 按 DCT 档位;PNG 逐行 inflate 丢行丢列;
|
||||
* BMP 按行 seek 跳采样)。峰值只与输出尺寸相关。
|
||||
* 不支持/失败/几乎等尺寸(4 分量 CMYK、算术编码、交错 PNG、RLE BMP、小图…)返回 0 →
|
||||
* 落回下面的 stb 旧路径,对外语义与档位表现不变。 */
|
||||
{
|
||||
unsigned char *bp = NULL;
|
||||
int bw = 0, bh = 0;
|
||||
if (meow_img_backend_file(path, maxdim, &bw, &bh, &bp) && bp)
|
||||
return img_finish_dim(bp, bw, bh, maxdim);
|
||||
}
|
||||
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));
|
||||
unsigned char *p = stbi_load_scaled(path, &w, &h, &c, 4, meow_img_pick_scale(longside, maxdim));
|
||||
return img_finish_dim(p, w, h, maxdim);
|
||||
}
|
||||
|
||||
/* 追加(M22):档位由调用方指定。与 meow_img_load_file_dim 同语义(结果长边 ≤ maxdim,
|
||||
* 超了再精修一次),只是档位不再由 maxdim 反推 —— 内存预算紧时可选更粗的档位。
|
||||
* M27:真缩解后端优先(step 折算成目标长边 ceil(长边/step),后端按该长边选 DCT 阶,
|
||||
* 峰值只与输出尺寸相关);后端不支持时回退 stbi_load_scaled(step),语义与 M22 一致。
|
||||
*
|
||||
* M27 r1(P1-1):allow_stb_fallback=0 时只尝试后端,**绝不回退 stb**——阅读器的门控按
|
||||
* 「后端峰值」放行时必须走这里,否则「头部说支持、解码中途失败」会静默落到 stb,
|
||||
* 实测可放出 18–36MB(截断 12MP JPEG / 头-only BMP / 非法位深 PNG),即 M22 的 SIGKILL 场景。
|
||||
* 后端失败返回 NULL(调用方按坏图占位)。 */
|
||||
meow_img *meow_img_load_file_step_ex(const char *path, int maxdim, int step,
|
||||
int allow_stb_fallback, int *used_backend)
|
||||
{
|
||||
if (used_backend) *used_backend = 0;
|
||||
if (!path) return NULL;
|
||||
if (step <= 1 && maxdim <= 0)
|
||||
return allow_stb_fallback ? meow_img_load_file(path) : NULL;
|
||||
if (step <= 0) step = 1;
|
||||
if (step > 8) step = 8;
|
||||
int w = 0, h = 0, c = 0;
|
||||
if (!stbi_info(path, &w, &h, &c)) return NULL;
|
||||
int longside = w > h ? w : h;
|
||||
if (step == 1 && maxdim <= 0)
|
||||
return allow_stb_fallback ? meow_img_load_file(path) : NULL;
|
||||
/* 追加(M23/M27):真缩解后端优先(JPEG/PNG/BMP 全部格式)。step 是「输出别比这个档位
|
||||
* 更细」的提示:折算成目标长边 ceil(长边/step) 传给后端(后端按该长边自动选 DCT 阶),
|
||||
* 与下面 stbi_load_scaled(step) 的语义一致,峰值只与输出尺寸相关;maxdim<=0 时不精修,
|
||||
* 结果仍是档位尺寸。后端不支持(CMYK/算术编码/交错/RLE…)时回退 stb,行为与 M22 一致。
|
||||
* M27 起阅读器的峰值模型已与后端同口径(page_source 的 reader_estimate_peak),
|
||||
* 所以 PNG/BMP 也一并接后端——这正是「修好了却用不上」的最后一处缝。 */
|
||||
{
|
||||
int eff = maxdim > 0 ? maxdim : longside;
|
||||
int step_cap = (longside + step - 1) / step;
|
||||
unsigned char *bp = NULL;
|
||||
int bw = 0, bh = 0;
|
||||
if (step_cap > 0 && step_cap < eff) eff = step_cap;
|
||||
if (eff > 0 && meow_img_backend_file(path, eff, &bw, &bh, &bp) && bp) {
|
||||
if (used_backend) *used_backend = 1;
|
||||
return img_finish_dim(bp, bw, bh, maxdim > 0 ? maxdim : longside);
|
||||
}
|
||||
}
|
||||
if (!allow_stb_fallback) return NULL; /* P1-1:门控按后端放行的页,失败即坏图 */
|
||||
unsigned char *p = stbi_load_scaled(path, &w, &h, &c, 4, step);
|
||||
/* maxdim<=0:不精修(保留档位输出的原始尺寸)。 */
|
||||
return img_finish_dim(p, w, h, maxdim > 0 ? maxdim : longside);
|
||||
}
|
||||
|
||||
meow_img *meow_img_load_file_step(const char *path, int maxdim, int step)
|
||||
{
|
||||
/* 通用入口保持 M22 语义:后端失败允许回退 stb。 */
|
||||
return meow_img_load_file_step_ex(path, maxdim, step, 1, NULL);
|
||||
}
|
||||
|
||||
/* 追加(M22):精确重采样到目标尺寸(最近邻,双向)。阅读器把缩解档位的结果一次性
|
||||
* 落到显示框,之后命中页就是单次原生 blit(M17 的热路径纪律不被粗档位破坏)。 */
|
||||
static unsigned char *scale_buf(const meow_img *im, int dw, int dh, int cover);
|
||||
|
||||
meow_img *meow_img_resample(meow_img *im, int w, int h)
|
||||
{
|
||||
if (!im || w <= 0 || h <= 0) return NULL;
|
||||
if (im->w == w && im->h == h) return NULL;
|
||||
unsigned char *tmp = scale_buf(im, w, h, 0);
|
||||
if (!tmp) return NULL;
|
||||
return img_alloc(w, h, tmp);
|
||||
}
|
||||
|
||||
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);
|
||||
/* 追加(M23):同文件入口,后端直接从调用方缓冲解码(不再整幅解 + 重采样)。 */
|
||||
{
|
||||
unsigned char *bp = NULL;
|
||||
int bw = 0, bh = 0;
|
||||
if (meow_img_backend_mem(buf, (size_t)len, maxdim, &bw, &bh, &bp) && bp)
|
||||
return img_finish_dim(bp, bw, bh, maxdim);
|
||||
}
|
||||
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));
|
||||
meow_img_pick_scale(longside, maxdim));
|
||||
return img_finish_dim(p, w, h, maxdim);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user