Merge branch 'feat/m26-sdk-image-stack-into-main-repo'
This commit is contained in:
commit
db672cbe8f
32 files changed
+3302
-64
No files matched your search
@@ -44,7 +44,7 @@ FT_INCS="-I$FT_BUILD -I$FT_BUILD/include -I$FT_SRC/include"
|
|||||||
rm -f meow_ui.a *.o
|
rm -f meow_ui.a *.o
|
||||||
|
|
||||||
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
# -I../meow_launcherd:meow_notify_ipc.c 复用共享协议头 meow_ipc.h(同一份、杜绝两端漂移)
|
||||||
OBJS="meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov"
|
OBJS="meow_ui_time meow_ui_gfx meow_ui_log meow_ui_notify meow_notify_ipc meow_ui_img meow_jpeg meow_png_stream meow_ui_widget meow_ui_input meow_ui_theme meow_ui_ime meow_pinyin meow_ui_sys meow_ui_vol meow_ui_activity meow_ui_global meow_ui_dialog meow_ui_config meow_ui_draw meow_ui_view meow_ui_nav meow_ui_media meow_ui_audio stb_image meow_ui_box meow_ui_anim meow_ui_scroll meow_lazygrid meow_select meow_ui_str meow_ui_ft meow_net_ipc meow_cachegov"
|
||||||
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
CFLAGS="-Os -static -I$ROOT/patch_v2/meow_launcherd"
|
||||||
for f in $OBJS; do
|
for f in $OBJS; do
|
||||||
echo "== cc $f =="
|
echo "== cc $f =="
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:MEOW_UI_DUMP=/tmp/demo_box.ppm ./demo_box_scroll
|
* 运行:MEOW_UI_DUMP=/tmp/demo_box.ppm ./demo_box_scroll
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -50,6 +50,24 @@ void meow_ui_flush_region(int x, int y, int w, int h); /* 只刷新指定区 *
|
|||||||
/* 半透明(blend565:前景按 alpha 与背景混叠) */
|
/* 半透明(blend565:前景按 alpha 与背景混叠) */
|
||||||
void meow_ui_fill_rect_alpha(int x, int y, int w, int h, uint32_t color, int alpha); /* 0-255 */
|
void meow_ui_fill_rect_alpha(int x, int y, int w, int h, uint32_t color, int alpha); /* 0-255 */
|
||||||
|
|
||||||
|
/* ---- RGB565 页图(M32)----
|
||||||
|
* 页槽常驻 RGB565(2 字节/像素):真机 480×853 页 1599KB → 800KB。
|
||||||
|
* 量化与 back_buf 用同一个 565 转换(逐位截断),565 屏上最终像素与 RGBA blit
|
||||||
|
* 路径逐像素一致——不引入色偏、不会比现在多出色带。
|
||||||
|
* 命中页(页图尺寸 == 显示尺寸)走 meow_gfx_blit_rgb565:每行一次拷贝,无重采样。
|
||||||
|
*
|
||||||
|
* alpha:565 页图**按不透明**处理(alpha 被忽略)。漫画页解码后 alpha 恒为 255,
|
||||||
|
* 与旧路径等价;带透明像素的 PNG(调色板/tRNS/color type 6、或 32bpp BMP)会有可见
|
||||||
|
* 差异:旧 RGBA 路径把透明像素混合到阅读器底色,565 路径直接画它的 RGB(通常是黑)。
|
||||||
|
* 若将来要支持透明页,需要在上屏时按 alpha 混合(而不是在落槽时丢通道)。 */
|
||||||
|
uint16_t meow_gfx_rgb565(uint32_t rgb); /* 24-bit RGB → 565(与 back_buf 同式) */
|
||||||
|
void meow_gfx_rgba_to_rgb565(const uint8_t *rgba, uint16_t *out, int npx); /* 不透明像素(忽略 alpha) */
|
||||||
|
/* 原生尺寸 blit(不透明):16bpp back_buf 上是每行一次 memcpy。 */
|
||||||
|
void meow_gfx_blit_rgb565(int x, int y, int w, int h, const uint16_t *px);
|
||||||
|
/* 最近邻缩放 blit(几何不符时的兜底;采样点与 meow_img_resample 同式)。 */
|
||||||
|
void meow_gfx_blit_rgb565_scaled(int x, int y, int w, int h,
|
||||||
|
int sw, int sh, const uint16_t *px);
|
||||||
|
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
/* §7 动画/时间(B1 最小可用) */
|
/* §7 动画/时间(B1 最小可用) */
|
||||||
/* ============================================================ */
|
/* ============================================================ */
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* meow_ui_image.h — SDK 图片层(§4,B1)。
|
* meow_ui_image.h — SDK 图片层(§4,B1)。
|
||||||
*
|
*
|
||||||
* 原 meow_ui.h 拆分的一部分(image 模块)。内部 stb_image(单头文件,静态编入 meow_ui.a)
|
* 原 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)。
|
* 解 PNG/JPEG/BMP,统一转 RGBA。meow_img 为不透明句柄(前向声明见 meow_ui_types.h)。
|
||||||
*/
|
*/
|
||||||
#ifndef MEOW_UI_IMAGE_H
|
#ifndef MEOW_UI_IMAGE_H
|
||||||
@@ -26,14 +27,56 @@ void meow_img_free(meow_img *img);
|
|||||||
* App 可用它在加载前判断「图太大」并给用户提示,而不必先撞 OOM。 */
|
* App 可用它在加载前判断「图太大」并给用户提示,而不必先撞 OOM。 */
|
||||||
int meow_img_probe_file(const char *path, int *w, int *h, int *channels);
|
int meow_img_probe_file(const char *path, int *w, int *h, int *channels);
|
||||||
|
|
||||||
/* 追加(M12)预算解码:解码期受长边约束,返回图最长边 ≤ maxdim。
|
/* 追加(M12/M23)预算解码:解码期受长边约束,返回图最长边 ≤ maxdim,尺寸与
|
||||||
* JPEG:按 1/2、1/4、1/8 整数步长抽取解码(stbi_load_scaled),整幅原尺寸 RGBA 缓冲从不物化,
|
* 「meow_img_load_file + meow_img_downscale(maxdim)」逐字节同口径(公式一致)。
|
||||||
* 峰值 ≈ 亮度分量平面 + 缩解输出 + 单行缓冲;随后用 meow_img_downscale 精修到 maxdim。
|
*
|
||||||
* PNG/BMP 等 stb 无解码期缩放能力的格式:整幅解码后立即降采样(峰值同旧入口,见 M12 报告)。
|
* 实现(M23 起):先进真缩解后端(内部 meow_jpeg.c / meow_png_stream.c),解码期只算目标分辨率:
|
||||||
* 小图(长边 ≤ maxdim)走旧路径,与原 API 完全一致;maxdim<=0 等价旧入口。失败返回 NULL。 */
|
* 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_file_dim(const char *path, int maxdim);
|
||||||
meow_img *meow_img_load_mem_dim(const void *buf, int len, 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_w(const meow_img *img);
|
||||||
int meow_img_h(const meow_img *img);
|
int meow_img_h(const meow_img *img);
|
||||||
/* 访问器:取 RGBA 像素指针(4 通道 straight alpha;供取色/直读像素)。meow_img 对外 opaque,
|
/* 访问器:取 RGBA 像素指针(4 通道 straight alpha;供取色/直读像素)。meow_img 对外 opaque,
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* meow_jpeg.h — M23 真缩解后端内部接口(**不对外导出**,不在 meow_ui.h 伞头里)。
|
||||||
|
*
|
||||||
|
* 后端直接产出「目标显示尺寸」的 RGBA,不做「先整幅解、再重采样」:
|
||||||
|
* - JPEG(meow_jpeg.c):DCT 域缩解 1/8、1/4、1/2(N=1/2/4 点 IDCT),渐进式只解到
|
||||||
|
* 首个精细化扫描(首个 Ah>0)为止——低频带此时已完整,再往后只是为了更细的量化精度。
|
||||||
|
* - PNG(meow_png_stream.c):libz inflate 逐行 defilter,按步长丢行丢列直写目标尺寸。
|
||||||
|
* - BMP(meow_png_stream.c):按行 seek + 行内跳列(同一套「只碰需要的行」思路)。
|
||||||
|
* 三者峰值都只与「输出尺寸 + 目标图像」相关,不随源图分辨率线性增长——**前提是文件头
|
||||||
|
* 声明的尺寸在合理范围内**:畸形/超大声明尺寸(例如 23 字节的 SOF 声明 65535×65535)会被
|
||||||
|
* 直接拒绝(返回 0 → 回退 stb,安全失败),不会按声明尺寸分配平面。
|
||||||
|
*
|
||||||
|
* 不支持的特性一律返回 0,由 meow_ui_img.c 回退 stb(行为与 M23 之前完全一致):
|
||||||
|
* 4 分量 CMYK/YCCK、算术编码/无损/分层 JPEG、Adam7 交错 PNG、1/2/4bpp 与 RLE BMP 等。
|
||||||
|
*
|
||||||
|
* 许可证:本文件与 meow_jpeg.c / meow_png_stream.c 为 MeowOS 自写代码(MIT,随 SDK 发布)。
|
||||||
|
* 不引入第三方解码器源码——理由见 M23 报告「为什么不用 IJG libjpeg」:libjpeg 系列对
|
||||||
|
* 渐进式 JPEG 必须整幅驻留系数阵列(≈1 字节/源像素/分量),正是审计里 +23.5MB 的来源,
|
||||||
|
* 换成它也无法把渐进式峰值压到 2.5MB 以内。
|
||||||
|
*/
|
||||||
|
#ifndef MEOW_JPEG_H
|
||||||
|
#define MEOW_JPEG_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 解码 path / 内存里的图,直接产出「长边 ≤ maxdim 且按 meow_img_downscale 同一公式等比缩放」
|
||||||
|
* 的 tw×th RGBA(4 通道 straight alpha,malloc 分配,调用方 free)。
|
||||||
|
* 返回 1 成功(tw/th/rgba 已填);0 = 不支持/失败/不需要(调用方回退 stb 或旧入口)。 */
|
||||||
|
int meow_img_backend_file(const char *path, int maxdim, int *tw, int *th, unsigned char **rgba);
|
||||||
|
int meow_img_backend_mem(const void *buf, size_t len, int maxdim, int *tw, int *th, unsigned char **rgba);
|
||||||
|
|
||||||
|
/* 目标尺寸:与 meow_img_downscale 同一公式(长边 = maxdim,短边按比例截断,下限 1)。 */
|
||||||
|
void meow_img_target_dims(int w, int h, int maxdim, int *tw, int *th);
|
||||||
|
|
||||||
|
/* meow_png_stream.c 提供(PNG 逐行 inflate / BMP 按行跳采样)。f 与 mem 二选一:
|
||||||
|
* f != NULL 走文件流(只读需要的行/块),否则从 mem[0..len) 读。 */
|
||||||
|
int meow_png_decode_stream(FILE *f, const unsigned char *mem, size_t len,
|
||||||
|
int maxdim, int *tw, int *th, unsigned char **rgba);
|
||||||
|
int meow_bmp_decode_stream(FILE *f, const unsigned char *mem, size_t len,
|
||||||
|
int maxdim, int *tw, int *th, unsigned char **rgba);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* MEOW_JPEG_H */
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
/*
|
||||||
|
* meow_png_stream.c — M23 真缩解后端(二):PNG 逐行 inflate + BMP 按行跳采样。
|
||||||
|
*
|
||||||
|
* 为什么不用 stb 的 PNG 路径:stb 先整幅 inflate + 反滤波成 raw,再展开成 RGBA 整幅,
|
||||||
|
* 最后才降采样——1600×2400 PNG 实测 +26.2MB。这里改成「按行流式」:
|
||||||
|
* - IDAT 边到边 inflate,一次只持有一行(filter 字节 + rowbytes)与上一行;
|
||||||
|
* - 反滤波后**只把需要的列**写进目标行(最近邻,与 meow_img_downscale 同口径);
|
||||||
|
* - 不需要的行整行丢弃(但仍要反滤波,filter 依赖上一行);
|
||||||
|
* - 峰值 ≈ 两行缓冲 + zlib 窗口(32KB) + 目标 RGBA,与源图分辨率无关。
|
||||||
|
* 支持:gray / gray+A / RGB / RGBA / 调色板,bit depth 1/2/4/8/16(16bit 取高字节降 8bit),
|
||||||
|
* tRNS 透明。不支持 → 返回 0 回退 stb:Adam7 交错、非 0 压缩/滤波方法、异常色型组合。
|
||||||
|
*
|
||||||
|
* BMP:文件流按目标行直接 seek 到源行(不读全图),行内跳列采样。支持 8bpp 调色板 /
|
||||||
|
* 16bpp RGB555 / 24bpp / 32bpp(BI_RGB);RLE、BITFIELDS、1/2/4bpp → 回退 stb。
|
||||||
|
*
|
||||||
|
* 许可证:MeowOS 自写(MIT,随 SDK 发布)。PNG/zlib 语义参考 RFC 2083 / zlib 手册;
|
||||||
|
* BMP 布局参考 stb_image 的解析口径(同为本仓已有依赖,行为对齐)。
|
||||||
|
*/
|
||||||
|
#include "meow_jpeg.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <limits.h> /* LONG_MAX:BMP 按行 seek 的 32 位偏移上限 */
|
||||||
|
|
||||||
|
/* ---------------- zlib ABI ---------------- */
|
||||||
|
#if defined(__has_include)
|
||||||
|
# if __has_include(<zlib.h>)
|
||||||
|
# include <zlib.h>
|
||||||
|
# define MZP_HAVE_H 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef MZP_HAVE_H
|
||||||
|
/* 设备 musl sysroot 没有 zlib.h(meow_font.c 同此口径):按 libz.a 的 ABI 声明最小 API。
|
||||||
|
* 指针/unsigned long 交给编译器定尺寸,宿主 64 位与设备 32 位都成立。 */
|
||||||
|
typedef unsigned char mzp_Bytef;
|
||||||
|
typedef unsigned int mzp_uInt;
|
||||||
|
typedef unsigned long mzp_uLong;
|
||||||
|
typedef void *mzp_voidpf;
|
||||||
|
typedef struct mzp_stream_s {
|
||||||
|
mzp_Bytef *next_in; mzp_uInt avail_in; mzp_uLong total_in;
|
||||||
|
mzp_Bytef *next_out; mzp_uInt avail_out; mzp_uLong total_out;
|
||||||
|
char *msg;
|
||||||
|
void *state;
|
||||||
|
void *zalloc;
|
||||||
|
void *zfree;
|
||||||
|
mzp_voidpf opaque;
|
||||||
|
int data_type;
|
||||||
|
mzp_uLong adler;
|
||||||
|
mzp_uLong reserved;
|
||||||
|
} mzp_stream;
|
||||||
|
extern int inflateInit_(mzp_stream *, const char *, int);
|
||||||
|
extern int inflate(mzp_stream *, int);
|
||||||
|
extern int inflateEnd(mzp_stream *);
|
||||||
|
extern const char *zlibVersion(void);
|
||||||
|
# define z_stream mzp_stream
|
||||||
|
# define Z_OK 0
|
||||||
|
# define Z_STREAM_END 1
|
||||||
|
# define Z_NO_FLUSH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---------------- ILP32 尺寸算术守卫 ----------------
|
||||||
|
* mipsel / arm-linux-musleabi 上 long 与 size_t 都是 32 位:把「声明尺寸 × bpp」这类
|
||||||
|
* 乘积直接放在 long 里会回绕成小值或 0。实测(ARM32):54 字节 BMP 头声明 w=2^27、
|
||||||
|
* bpp=32 → w*bpp = 2^32 = 0 → rowsize = 0 → malloc(0) → 采样索引 row + sx*4 越界读
|
||||||
|
* → SIGSEGV;同一文件在 LP64 宿主返回 NULL,所以宿主测试天然看不到这类。
|
||||||
|
* 因此:凡「由文件头算出来的字节数/偏移」一律升到 unsigned long long 再验,
|
||||||
|
* 超限即返回 0,由调用方回退 stb(安全失败,与 M26 之前的行为一致)。
|
||||||
|
* 单边上限 1<<20(1,048,576):远超真实 BMP/PNG 声明尺寸,同时保证行字节数
|
||||||
|
* (≤4 MiB)、行偏移与目标 RGBA 都不会在 32 位溢出。 */
|
||||||
|
#define MZP_MAX_DIM (1u << 20)
|
||||||
|
static int mzp_bytes_ok(unsigned long long n)
|
||||||
|
{
|
||||||
|
return n > 0 && n <= (unsigned long long)(size_t)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- 字节源 ---------------- */
|
||||||
|
typedef struct {
|
||||||
|
FILE *f;
|
||||||
|
const unsigned char *mem;
|
||||||
|
size_t memlen, mempos;
|
||||||
|
} png_src;
|
||||||
|
|
||||||
|
static int ps_read(png_src *s, void *dst, size_t n)
|
||||||
|
{
|
||||||
|
if (s->mem) {
|
||||||
|
if (s->mempos + n > s->memlen) return 0;
|
||||||
|
memcpy(dst, s->mem + s->mempos, n);
|
||||||
|
s->mempos += n;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return fread(dst, 1, n, s->f) == n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ps_skip(png_src *s, size_t n)
|
||||||
|
{
|
||||||
|
if (s->mem) {
|
||||||
|
if (s->mempos + n > s->memlen) return 0;
|
||||||
|
s->mempos += n;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return fseek(s->f, (long)n, SEEK_CUR) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* PNG */
|
||||||
|
/* ================================================================== */
|
||||||
|
typedef struct {
|
||||||
|
png_src src;
|
||||||
|
z_stream z;
|
||||||
|
int z_ready, z_end;
|
||||||
|
unsigned w, h;
|
||||||
|
int depth, color;
|
||||||
|
int bits; /* 每像素位数 */
|
||||||
|
size_t rowbytes;
|
||||||
|
unsigned char *line; /* 1 filter 字节 + rowbytes */
|
||||||
|
unsigned char *prev; /* 上一行的像素字节 */
|
||||||
|
unsigned char *cur; /* 本行的像素字节 */
|
||||||
|
size_t need, got;
|
||||||
|
unsigned char pal[256][3];
|
||||||
|
unsigned char trns_a[256]; /* 调色板透明度 */
|
||||||
|
int pal_n;
|
||||||
|
int have_trns;
|
||||||
|
unsigned trns[3]; /* gray / RGB 的 tRNS 值(已降到 8bit) */
|
||||||
|
unsigned char *out;
|
||||||
|
int tw, th;
|
||||||
|
int next_ty;
|
||||||
|
unsigned y;
|
||||||
|
} png_ctx;
|
||||||
|
|
||||||
|
/* 从行里取 px 列的 8bit 通道;返回通道数(写入 o[0..3] 的 RGB(A) 语义由调用方定)。 */
|
||||||
|
static void png_get_px(const png_ctx *c, const unsigned char *row, int x, unsigned char *o)
|
||||||
|
{
|
||||||
|
int d = c->depth;
|
||||||
|
if (d < 8) {
|
||||||
|
int per = 8 / d; /* 每字节像素数 */
|
||||||
|
int byte = x / per;
|
||||||
|
int shift = 8 - d * (x % per + 1);
|
||||||
|
int v = (row[byte] >> shift) & ((1 << d) - 1);
|
||||||
|
if (c->color == 3) { /* 调色板:子字节值即索引 */
|
||||||
|
o[0] = c->pal[v][0]; o[1] = c->pal[v][1]; o[2] = c->pal[v][2];
|
||||||
|
o[3] = c->trns_a[v];
|
||||||
|
} else {
|
||||||
|
unsigned char g = (unsigned char)(v * 255 / ((1 << d) - 1));
|
||||||
|
o[0] = o[1] = o[2] = g;
|
||||||
|
/* tRNS 存的是原始采样值(0..2^d-1),不是展开后的 0..255 */
|
||||||
|
o[3] = (c->color == 0 && c->have_trns && (unsigned)v == c->trns[0]) ? 0 : 255;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (d == 8) {
|
||||||
|
if (c->color == 0) { /* gray */
|
||||||
|
o[0] = o[1] = o[2] = row[x];
|
||||||
|
o[3] = (c->have_trns && row[x] == c->trns[0]) ? 0 : 255;
|
||||||
|
} else if (c->color == 2) { /* RGB */
|
||||||
|
o[0] = row[x * 3]; o[1] = row[x * 3 + 1]; o[2] = row[x * 3 + 2];
|
||||||
|
o[3] = (c->have_trns && row[x * 3] == c->trns[0] &&
|
||||||
|
row[x * 3 + 1] == c->trns[1] && row[x * 3 + 2] == c->trns[2]) ? 0 : 255;
|
||||||
|
} else if (c->color == 3) { /* palette */
|
||||||
|
int i = row[x];
|
||||||
|
o[0] = c->pal[i][0]; o[1] = c->pal[i][1]; o[2] = c->pal[i][2];
|
||||||
|
o[3] = c->trns_a[i];
|
||||||
|
} else if (c->color == 4) { /* gray + A */
|
||||||
|
o[0] = o[1] = o[2] = row[x * 2];
|
||||||
|
o[3] = row[x * 2 + 1];
|
||||||
|
} else { /* RGBA */
|
||||||
|
o[0] = row[x * 4]; o[1] = row[x * 4 + 1];
|
||||||
|
o[2] = row[x * 4 + 2]; o[3] = row[x * 4 + 3];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* 16bit:取高字节 */
|
||||||
|
if (c->color == 0) {
|
||||||
|
o[0] = o[1] = o[2] = row[x * 2];
|
||||||
|
o[3] = (c->have_trns && row[x * 2] == c->trns[0]) ? 0 : 255;
|
||||||
|
} else if (c->color == 2) {
|
||||||
|
o[0] = row[x * 6]; o[1] = row[x * 6 + 2]; o[2] = row[x * 6 + 4];
|
||||||
|
o[3] = (c->have_trns && row[x * 6] == c->trns[0] &&
|
||||||
|
row[x * 6 + 2] == c->trns[1] && row[x * 6 + 4] == c->trns[2]) ? 0 : 255;
|
||||||
|
} else if (c->color == 4) {
|
||||||
|
o[0] = o[1] = o[2] = row[x * 4];
|
||||||
|
o[3] = row[x * 4 + 2];
|
||||||
|
} else {
|
||||||
|
o[0] = row[x * 8]; o[1] = row[x * 8 + 2];
|
||||||
|
o[2] = row[x * 8 + 4]; o[3] = row[x * 8 + 6];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 一行反滤波完成后:按需写目标行。 */
|
||||||
|
static int png_emit_row(png_ctx *c)
|
||||||
|
{
|
||||||
|
unsigned char ft = c->line[0];
|
||||||
|
const unsigned char *src = c->line + 1;
|
||||||
|
unsigned char *dst = c->cur;
|
||||||
|
size_t x, bpp = (size_t)((c->bits + 7) / 8);
|
||||||
|
if (bpp < 1) bpp = 1;
|
||||||
|
if (ft > 4) return 0;
|
||||||
|
for (x = 0; x < c->rowbytes; x++) {
|
||||||
|
unsigned char left = (x >= bpp) ? dst[x - bpp] : 0;
|
||||||
|
unsigned char up = c->prev ? c->prev[x] : 0;
|
||||||
|
unsigned char ul = (c->prev && x >= bpp) ? c->prev[x - bpp] : 0;
|
||||||
|
unsigned char v = src[x];
|
||||||
|
switch (ft) {
|
||||||
|
case 0: dst[x] = v; break;
|
||||||
|
case 1: dst[x] = (unsigned char)(v + left); break;
|
||||||
|
case 2: dst[x] = (unsigned char)(v + up); break;
|
||||||
|
case 3: dst[x] = (unsigned char)(v + (((unsigned)left + (unsigned)up) >> 1)); break;
|
||||||
|
default: {
|
||||||
|
int p = (int)left + (int)up - (int)ul;
|
||||||
|
int pa = p - (int)left; if (pa < 0) pa = -pa;
|
||||||
|
int pb = p - (int)up; if (pb < 0) pb = -pb;
|
||||||
|
int pc = p - (int)ul; if (pc < 0) pc = -pc;
|
||||||
|
unsigned char pred = (pa <= pb && pa <= pc) ? left : (pb <= pc ? up : ul);
|
||||||
|
dst[x] = (unsigned char)(v + pred);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c->next_ty < c->th) {
|
||||||
|
long long sy = (long long)c->next_ty * (long long)c->h / c->th; /* 64 位:ILP32 上 *h 会溢出 */
|
||||||
|
if (sy == (long long)c->y) {
|
||||||
|
unsigned char *o = c->out +
|
||||||
|
(size_t)((unsigned long long)c->next_ty * (unsigned long long)c->tw * 4u);
|
||||||
|
int tx;
|
||||||
|
for (tx = 0; tx < c->tw; tx++) {
|
||||||
|
long long sxl = (long long)tx * (long long)c->w / c->tw;
|
||||||
|
int sx = (int)(sxl < 0 ? 0
|
||||||
|
: (sxl >= (long long)c->w ? (long long)c->w - 1 : sxl));
|
||||||
|
unsigned char px[4];
|
||||||
|
png_get_px(c, dst, sx, px);
|
||||||
|
o[tx * 4] = px[0]; o[tx * 4 + 1] = px[1];
|
||||||
|
o[tx * 4 + 2] = px[2]; o[tx * 4 + 3] = px[3];
|
||||||
|
}
|
||||||
|
c->next_ty++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 交换 prev/cur(prev 直接成为反滤波基准) */
|
||||||
|
{
|
||||||
|
unsigned char *t = c->prev;
|
||||||
|
c->prev = c->cur;
|
||||||
|
c->cur = t;
|
||||||
|
}
|
||||||
|
c->y++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PNG_NEED_MORE 2
|
||||||
|
|
||||||
|
static int png_pump(png_ctx *c)
|
||||||
|
{
|
||||||
|
while (c->got < c->need) {
|
||||||
|
int ret;
|
||||||
|
c->z.next_out = c->line + c->got;
|
||||||
|
c->z.avail_out = (unsigned)(c->need - c->got);
|
||||||
|
ret = inflate(&c->z, Z_NO_FLUSH);
|
||||||
|
c->got = c->need - c->z.avail_out;
|
||||||
|
if (ret == Z_STREAM_END) c->z_end = 1;
|
||||||
|
else if (ret != Z_OK) return 0;
|
||||||
|
if (c->got < c->need && (c->z.avail_in == 0 || c->z_end))
|
||||||
|
return c->z_end ? 0 : PNG_NEED_MORE;
|
||||||
|
}
|
||||||
|
if (!png_emit_row(c)) return 0;
|
||||||
|
c->got = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int png_bits_of(int color, int depth)
|
||||||
|
{
|
||||||
|
switch (color) {
|
||||||
|
case 0: return depth; /* gray */
|
||||||
|
case 2: return depth * 3; /* rgb */
|
||||||
|
case 3: return depth; /* palette */
|
||||||
|
case 4: return depth * 2; /* gray + a */
|
||||||
|
case 6: return depth * 4; /* rgba */
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int meow_png_decode_stream(FILE *f, const unsigned char *mem, size_t len,
|
||||||
|
int maxdim, int *tw, int *th, unsigned char **rgba)
|
||||||
|
{
|
||||||
|
png_ctx c;
|
||||||
|
unsigned char sig[8], hdr[8];
|
||||||
|
unsigned char ibuf[4096];
|
||||||
|
int have_ihdr = 0, i, ok = 0;
|
||||||
|
|
||||||
|
if (maxdim <= 0) return 0;
|
||||||
|
memset(&c, 0, sizeof c);
|
||||||
|
c.src.f = f;
|
||||||
|
c.src.mem = mem;
|
||||||
|
c.src.memlen = len;
|
||||||
|
if (!ps_read(&c.src, sig, 8)) return 0;
|
||||||
|
if (memcmp(sig, "\x89PNG\r\n\x1a\n", 8) != 0) return 0;
|
||||||
|
|
||||||
|
while (ps_read(&c.src, hdr, 8)) {
|
||||||
|
unsigned clen = ((unsigned)hdr[0] << 24) | ((unsigned)hdr[1] << 16) |
|
||||||
|
((unsigned)hdr[2] << 8) | hdr[3];
|
||||||
|
const unsigned char *type = hdr + 4;
|
||||||
|
if (clen > 0x7FFFFFFFu) return 0;
|
||||||
|
|
||||||
|
if (memcmp(type, "IHDR", 4) == 0) {
|
||||||
|
unsigned char d[13];
|
||||||
|
if (clen < 13 || have_ihdr) return 0;
|
||||||
|
if (!ps_read(&c.src, d, 13)) return 0;
|
||||||
|
c.w = ((unsigned)d[0] << 24) | ((unsigned)d[1] << 16) | ((unsigned)d[2] << 8) | d[3];
|
||||||
|
c.h = ((unsigned)d[4] << 24) | ((unsigned)d[5] << 16) | ((unsigned)d[6] << 8) | d[7];
|
||||||
|
c.depth = d[8];
|
||||||
|
c.color = d[9];
|
||||||
|
if (d[10] != 0 || d[11] != 0 || d[12] != 0) return 0; /* 只支持非交错 + 标准压缩/滤波 */
|
||||||
|
if (c.w == 0 || c.h == 0 || c.w > 65535u || c.h > 65535u) return 0;
|
||||||
|
if (!png_depth_ok(c.color, c.depth)) return 0;
|
||||||
|
c.bits = png_bits_of(c.color, c.depth);
|
||||||
|
c.rowbytes = ((size_t)c.w * c.bits + 7) / 8;
|
||||||
|
if (c.rowbytes == 0) return 0;
|
||||||
|
/* 小图不动:与 meow_img_load_file_dim 的「旧入口」判定一致 */
|
||||||
|
if ((long)(c.w > c.h ? c.w : c.h) <= maxdim) return 0;
|
||||||
|
if (clen > 13 && !ps_skip(&c.src, clen - 13)) return 0;
|
||||||
|
have_ihdr = 1;
|
||||||
|
c.need = c.rowbytes + 1;
|
||||||
|
c.line = (unsigned char *)malloc(c.need);
|
||||||
|
c.prev = (unsigned char *)malloc(c.rowbytes);
|
||||||
|
c.cur = (unsigned char *)malloc(c.rowbytes);
|
||||||
|
if (!c.line || !c.prev || !c.cur) goto done;
|
||||||
|
memset(c.prev, 0, c.rowbytes);
|
||||||
|
memset(c.cur, 0, c.rowbytes);
|
||||||
|
for (i = 0; i < 256; i++) c.trns_a[i] = 255;
|
||||||
|
meow_img_target_dims((int)c.w, (int)c.h, maxdim, &c.tw, &c.th);
|
||||||
|
{
|
||||||
|
/* ILP32 上 tw*th*4 会回绕(32768×32768×4 = 2^32 → 0 → malloc(0) 后越界写) */
|
||||||
|
unsigned long long ob = (unsigned long long)c.tw * (unsigned long long)c.th * 4u;
|
||||||
|
if (!mzp_bytes_ok(ob)) goto done;
|
||||||
|
c.out = (unsigned char *)malloc((size_t)ob);
|
||||||
|
if (!c.out) goto done;
|
||||||
|
memset(c.out, 0, (size_t)ob);
|
||||||
|
}
|
||||||
|
memset(&c.z, 0, sizeof c.z);
|
||||||
|
if (inflateInit_(&c.z, zlibVersion(), (int)sizeof c.z) != Z_OK) goto done;
|
||||||
|
c.z_ready = 1;
|
||||||
|
} else if (memcmp(type, "PLTE", 4) == 0) {
|
||||||
|
unsigned char d[256 * 3];
|
||||||
|
if (clen > sizeof d || clen % 3) return 0;
|
||||||
|
if (!ps_read(&c.src, d, clen)) return 0;
|
||||||
|
c.pal_n = (int)(clen / 3);
|
||||||
|
memcpy(c.pal, d, clen);
|
||||||
|
} else if (memcmp(type, "tRNS", 4) == 0) {
|
||||||
|
unsigned char d[256];
|
||||||
|
if (clen > sizeof d) return 0;
|
||||||
|
if (!ps_read(&c.src, d, clen)) return 0;
|
||||||
|
c.have_trns = 1;
|
||||||
|
if (c.color == 3) {
|
||||||
|
for (i = 0; i < (int)clen && i < 256; i++) c.trns_a[i] = d[i];
|
||||||
|
} else if (c.color == 0 && clen >= 2) {
|
||||||
|
/* 8bit/低位深:采样值存在低字节;16bit:与像素一样取高字节比较 */
|
||||||
|
c.trns[0] = (c.depth == 16) ? d[0] : d[1];
|
||||||
|
} else if (c.color == 2 && clen >= 6) {
|
||||||
|
if (c.depth == 16) {
|
||||||
|
c.trns[0] = d[0]; c.trns[1] = d[2]; c.trns[2] = d[4];
|
||||||
|
} else {
|
||||||
|
c.trns[0] = d[1]; c.trns[1] = d[3]; c.trns[2] = d[5];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (memcmp(type, "IDAT", 4) == 0) {
|
||||||
|
unsigned remain = clen;
|
||||||
|
if (!have_ihdr || !c.out) return 0;
|
||||||
|
while (remain) {
|
||||||
|
unsigned n = remain > sizeof ibuf ? (unsigned)sizeof ibuf : remain;
|
||||||
|
if (!ps_read(&c.src, ibuf, n)) goto done;
|
||||||
|
remain -= n;
|
||||||
|
c.z.next_in = ibuf;
|
||||||
|
c.z.avail_in = n;
|
||||||
|
while (c.z.avail_in && c.next_ty < c.th) {
|
||||||
|
int r = png_pump(&c);
|
||||||
|
if (r == 0) goto done;
|
||||||
|
if (r == PNG_NEED_MORE) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (memcmp(type, "IEND", 4) == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (clen && !ps_skip(&c.src, clen)) return 0;
|
||||||
|
}
|
||||||
|
/* 跳过 CRC */
|
||||||
|
{
|
||||||
|
unsigned char crc[4];
|
||||||
|
if (!ps_read(&c.src, crc, 4)) break;
|
||||||
|
}
|
||||||
|
if (c.out && c.next_ty >= c.th) break; /* 目标行都拿到了,不必读完 */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!have_ihdr || !c.out || c.next_ty < c.th) goto done;
|
||||||
|
if (c.color == 3 && c.pal_n <= 0) goto done;
|
||||||
|
*tw = c.tw;
|
||||||
|
*th = c.th;
|
||||||
|
*rgba = c.out;
|
||||||
|
c.out = NULL;
|
||||||
|
ok = 1;
|
||||||
|
done:
|
||||||
|
if (c.z_ready) inflateEnd(&c.z);
|
||||||
|
free(c.line);
|
||||||
|
free(c.prev);
|
||||||
|
free(c.cur);
|
||||||
|
free(c.out);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* BMP */
|
||||||
|
/* ================================================================== */
|
||||||
|
static unsigned le16(const unsigned char *p) { return (unsigned)p[0] | ((unsigned)p[1] << 8); }
|
||||||
|
static unsigned le32(const unsigned char *p)
|
||||||
|
{
|
||||||
|
return (unsigned)p[0] | ((unsigned)p[1] << 8) | ((unsigned)p[2] << 16) | ((unsigned)p[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
int meow_bmp_decode_stream(FILE *f, const unsigned char *mem, size_t len,
|
||||||
|
int maxdim, int *tw, int *th, unsigned char **rgba)
|
||||||
|
{
|
||||||
|
png_src src;
|
||||||
|
unsigned char fh[14], dh[4];
|
||||||
|
unsigned char dib[1024];
|
||||||
|
unsigned dibsize, dataoff, bpp, compression, colors;
|
||||||
|
long w, h, rowsize;
|
||||||
|
int topdown, i;
|
||||||
|
unsigned char pal[256][3];
|
||||||
|
unsigned char *row = NULL, *out = NULL;
|
||||||
|
int tw_ = 0, th_ = 0, ok = 0;
|
||||||
|
|
||||||
|
if (maxdim <= 0) return 0;
|
||||||
|
memset(&src, 0, sizeof src);
|
||||||
|
src.f = f;
|
||||||
|
src.mem = mem;
|
||||||
|
src.memlen = len;
|
||||||
|
if (!ps_read(&src, fh, 14)) return 0;
|
||||||
|
if (fh[0] != 'B' || fh[1] != 'M') return 0;
|
||||||
|
dataoff = le32(fh + 10);
|
||||||
|
if (!ps_read(&src, dh, 4)) return 0;
|
||||||
|
dibsize = le32(dh);
|
||||||
|
if (dibsize < 40 || dibsize > sizeof dib) return 0; /* BITMAPCOREHEADER/OS2 → stb */
|
||||||
|
memcpy(dib, dh, 4);
|
||||||
|
if (!ps_read(&src, dib + 4, dibsize - 4)) return 0;
|
||||||
|
bpp = le16(dib + 14);
|
||||||
|
compression = le32(dib + 16);
|
||||||
|
colors = (dibsize >= 36) ? le32(dib + 32) : 0;
|
||||||
|
if (compression != 0) return 0; /* RLE/BITFIELDS → stb */
|
||||||
|
if (bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) return 0;
|
||||||
|
/* 声明尺寸过 32 位算术闸(M26 r1 P1):w×bpp 与 tx×w 在 ILP32 上会回绕成小值/负数,
|
||||||
|
* 直接导致 malloc(0) + 越界读。h=INT_MIN 时 -h 同样溢出,故升到 long long 再取绝对值。 */
|
||||||
|
{
|
||||||
|
int wi = (int)le32(dib + 4);
|
||||||
|
int hi = (int)le32(dib + 8);
|
||||||
|
long long hll;
|
||||||
|
if (wi <= 0 || hi == 0) return 0;
|
||||||
|
topdown = hi < 0;
|
||||||
|
hll = topdown ? -(long long)hi : (long long)hi;
|
||||||
|
if ((unsigned long long)wi > MZP_MAX_DIM || hll <= 0 ||
|
||||||
|
(unsigned long long)hll > MZP_MAX_DIM) return 0; /* 离奇声明尺寸 → 回退 stb */
|
||||||
|
w = (long)wi;
|
||||||
|
h = (long)hll;
|
||||||
|
}
|
||||||
|
if ((long)(w > h ? w : h) <= maxdim) return 0; /* 小图走旧入口 */
|
||||||
|
|
||||||
|
if (bpp <= 8) {
|
||||||
|
unsigned n = colors ? colors : 256;
|
||||||
|
unsigned char e[4];
|
||||||
|
if (n > 256) n = 256;
|
||||||
|
for (i = 0; (unsigned)i < n; i++) {
|
||||||
|
if (!ps_read(&src, e, 4)) return 0;
|
||||||
|
pal[i][0] = e[2]; pal[i][1] = e[1]; pal[i][2] = e[0];
|
||||||
|
}
|
||||||
|
for (; i < 256; i++) pal[i][0] = pal[i][1] = pal[i][2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* 行字节数 64 位算(ILP32 上 w*bpp 在 w≥2^27/bpp 时回绕成 0) */
|
||||||
|
unsigned long long rb = ((unsigned long long)w * bpp + 31u) / 32u * 4u;
|
||||||
|
if (!mzp_bytes_ok(rb)) return 0;
|
||||||
|
rowsize = (long)rb; /* w ≤ MZP_MAX_DIM → ≤ 4 MiB */
|
||||||
|
}
|
||||||
|
meow_img_target_dims((int)w, (int)h, maxdim, &tw_, &th_);
|
||||||
|
row = (unsigned char *)malloc((size_t)rowsize);
|
||||||
|
{
|
||||||
|
unsigned long long ob = (unsigned long long)tw_ * (unsigned long long)th_ * 4u;
|
||||||
|
if (mzp_bytes_ok(ob)) out = (unsigned char *)malloc((size_t)ob);
|
||||||
|
}
|
||||||
|
if (!row || !out) goto done;
|
||||||
|
|
||||||
|
for (int ty = 0; ty < th_; ty++) {
|
||||||
|
long long sy = (long long)ty * h / th_;
|
||||||
|
long long file_row = topdown ? sy : ((long long)h - 1 - sy);
|
||||||
|
long long off = (long long)dataoff + file_row * (long long)rowsize;
|
||||||
|
unsigned char *o = out + (size_t)((unsigned long long)ty * (unsigned long long)tw_ * 4u);
|
||||||
|
if (src.mem) {
|
||||||
|
if (off < 0 ||
|
||||||
|
(unsigned long long)off + (unsigned long long)rowsize > (unsigned long long)src.memlen)
|
||||||
|
goto done;
|
||||||
|
memcpy(row, src.mem + (size_t)off, (size_t)rowsize);
|
||||||
|
} else {
|
||||||
|
if (off < 0 || off > (long long)LONG_MAX) goto done; /* fseek 只有 32 位偏移 */
|
||||||
|
if (fseek(src.f, (long)off, SEEK_SET) != 0) goto done;
|
||||||
|
if (fread(row, 1, (size_t)rowsize, src.f) != (size_t)rowsize) goto done;
|
||||||
|
}
|
||||||
|
for (int tx = 0; tx < tw_; tx++) {
|
||||||
|
long long sxl = (long long)tx * w / tw_;
|
||||||
|
int sx = (int)(sxl < 0 ? 0 : (sxl >= (long long)w ? (long long)w - 1 : sxl));
|
||||||
|
unsigned char *p = o + (size_t)tx * 4;
|
||||||
|
if (bpp == 24) {
|
||||||
|
const unsigned char *q = row + sx * 3;
|
||||||
|
p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; p[3] = 255;
|
||||||
|
} else if (bpp == 32) {
|
||||||
|
const unsigned char *q = row + sx * 4;
|
||||||
|
p[0] = q[2]; p[1] = q[1]; p[2] = q[0]; p[3] = 255; /* BI_RGB:alpha 不作为语义 */
|
||||||
|
} else if (bpp == 16) {
|
||||||
|
unsigned v = le16(row + sx * 2);
|
||||||
|
unsigned r = (v >> 10) & 31, g = (v >> 5) & 31, b = v & 31;
|
||||||
|
p[0] = (unsigned char)((r << 3) | (r >> 2));
|
||||||
|
p[1] = (unsigned char)((g << 3) | (g >> 2));
|
||||||
|
p[2] = (unsigned char)((b << 3) | (b >> 2));
|
||||||
|
p[3] = 255;
|
||||||
|
} else {
|
||||||
|
unsigned idx = row[sx];
|
||||||
|
p[0] = pal[idx & 255][0]; p[1] = pal[idx & 255][1];
|
||||||
|
p[2] = pal[idx & 255][2]; p[3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*tw = tw_;
|
||||||
|
*th = th_;
|
||||||
|
*rgba = out;
|
||||||
|
out = NULL;
|
||||||
|
ok = 1;
|
||||||
|
done:
|
||||||
|
free(row);
|
||||||
|
free(out);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
@@ -172,6 +172,9 @@ static void refresh_governor(unsigned long long cost_ms, int period)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 工具 ---- */
|
/* ---- 工具 ---- */
|
||||||
|
/* 时钟统一由 meow_ui_time.c 提供(meow_ui_time_ms,声明见 include/meow_ui_draw.h):
|
||||||
|
* mipsel 上 zig musl 的 time64 ABI 自相矛盾,取时必须走内核 o32 ABI 再升位,
|
||||||
|
* 故本 TU 不再保留取时实现(详见 sdk/CLOCK_ABI.md)。 */
|
||||||
static uint16_t rgb565(uint32_t c)
|
static uint16_t rgb565(uint32_t c)
|
||||||
{
|
{
|
||||||
return (uint16_t)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F));
|
return (uint16_t)(((c >> 8) & 0xF800) | ((c >> 5) & 0x07E0) | ((c >> 3) & 0x001F));
|
||||||
@@ -854,6 +857,106 @@ void meow_gfx_blit_rgba(int x, int y, int w, int h, const uint8_t *rgba, int alp
|
|||||||
dirty_add(x1, y1, x2 - x1, y2 - y1);
|
dirty_add(x1, y1, x2 - x1, y2 - y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================= RGB565 页图(M32) =================
|
||||||
|
* 阅读器页槽常驻 RGB565(2B/px)而不是 RGBA:真机 480×853 页 1599KB → 800KB。
|
||||||
|
* 量化与 back_buf 用同一个 rgb565()(逐位截断),所以 565 屏上落下的像素与旧的
|
||||||
|
* RGBA blit 路径**逐像素一致**——不引入色偏,也不会比现在多出色带。
|
||||||
|
* 命中页(解码/落框尺寸 == 显示尺寸)走 meow_gfx_blit_rgb565:每行一次 memcpy,
|
||||||
|
* 单次拷贝、没有每帧重采样。alpha 按不透明处理(页图 alpha 恒为 255;带透明像素的
|
||||||
|
* PNG/32bpp BMP 页会与旧 RGBA 路径不同——旧路径混合到底色,这里直接画 RGB)。 */
|
||||||
|
uint16_t meow_gfx_rgb565(uint32_t rgb)
|
||||||
|
{
|
||||||
|
return rgb565(rgb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void meow_gfx_rgba_to_rgb565(const uint8_t *rgba, uint16_t *out, int npx)
|
||||||
|
{
|
||||||
|
if (!rgba || !out || npx <= 0) return;
|
||||||
|
for (int i = 0; i < npx; i++) {
|
||||||
|
const uint8_t *p = rgba + (size_t)i * 4;
|
||||||
|
out[i] = rgb565(((uint32_t)p[0] << 16) | ((uint32_t)p[1] << 8) | (uint32_t)p[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 目标矩形与 clip 求交;返回 1=还有可画区域。 */
|
||||||
|
static int blit565_clip(int x, int y, int w, int h, int *x1, int *y1, int *x2, int *y2)
|
||||||
|
{
|
||||||
|
if (!g_init_ok || w <= 0 || h <= 0) return 0;
|
||||||
|
*x1 = x; *y1 = y; *x2 = x + w; *y2 = y + h;
|
||||||
|
if (*x1 < 0) *x1 = 0;
|
||||||
|
if (*y1 < 0) *y1 = 0;
|
||||||
|
if (*x2 > g_xres) *x2 = g_xres;
|
||||||
|
if (*y2 > g_yres) *y2 = g_yres;
|
||||||
|
if (g_clip_n > 0) {
|
||||||
|
int *c = g_clip_stack[g_clip_n - 1];
|
||||||
|
if (*x1 < c[0]) *x1 = c[0];
|
||||||
|
if (*y1 < c[1]) *y1 = c[1];
|
||||||
|
if (*x2 > c[2]) *x2 = c[2];
|
||||||
|
if (*y2 > c[3]) *y2 = c[3];
|
||||||
|
}
|
||||||
|
return *x2 > *x1 && *y2 > *y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void meow_gfx_blit_rgb565(int x, int y, int w, int h, const uint16_t *px)
|
||||||
|
{
|
||||||
|
if (!px) return;
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
if (!blit565_clip(x, y, w, h, &x1, &y1, &x2, &y2)) return;
|
||||||
|
int n = x2 - x1;
|
||||||
|
for (int py = y1; py < y2; py++) {
|
||||||
|
const uint16_t *src = px + (size_t)(py - y) * w + (x1 - x);
|
||||||
|
unsigned char *dst = g_fb + (size_t)py * g_line + (size_t)x1 * (size_t)(g_bpp / 8);
|
||||||
|
if (g_bpp == 16) {
|
||||||
|
memcpy(dst, src, (size_t)n * 2); /* 命中页:每行一次拷贝 */
|
||||||
|
} else {
|
||||||
|
uint32_t *d32 = (uint32_t *)dst;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
uint16_t c = src[i];
|
||||||
|
d32[i] = ((uint32_t)ex5((c >> 11) & 0x1F) << 24) |
|
||||||
|
((uint32_t)ex6((c >> 5) & 0x3F) << 16) |
|
||||||
|
((uint32_t)ex5(c & 0x1F) << 8) | 0xFFu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirty_add(x1, y1, n, y2 - y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 最近邻缩放(仅几何不符时的兜底路径;采样点与 meow_img_resample 同式)。
|
||||||
|
* 命中页不会走到这里——那是热路径纪律(M17/M32)。 */
|
||||||
|
void meow_gfx_blit_rgb565_scaled(int x, int y, int w, int h,
|
||||||
|
int sw, int sh, const uint16_t *px)
|
||||||
|
{
|
||||||
|
if (!px || sw <= 0 || sh <= 0) return;
|
||||||
|
int x1, y1, x2, y2;
|
||||||
|
if (!blit565_clip(x, y, w, h, &x1, &y1, &x2, &y2)) return;
|
||||||
|
int n = x2 - x1;
|
||||||
|
for (int py = y1; py < y2; py++) {
|
||||||
|
int sy = (int)((long long)(py - y) * sh / h);
|
||||||
|
if (sy >= sh) sy = sh - 1;
|
||||||
|
const uint16_t *row = px + (size_t)sy * sw;
|
||||||
|
unsigned char *dst = g_fb + (size_t)py * g_line + (size_t)x1 * (size_t)(g_bpp / 8);
|
||||||
|
if (g_bpp == 16) {
|
||||||
|
uint16_t *d16 = (uint16_t *)dst;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int sx = (int)((long long)(x1 + i - x) * sw / w);
|
||||||
|
if (sx >= sw) sx = sw - 1;
|
||||||
|
d16[i] = row[sx];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t *d32 = (uint32_t *)dst;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int sx = (int)((long long)(x1 + i - x) * sw / w);
|
||||||
|
if (sx >= sw) sx = sw - 1;
|
||||||
|
uint16_t c = row[sx];
|
||||||
|
d32[i] = ((uint32_t)ex5((c >> 11) & 0x1F) << 24) |
|
||||||
|
((uint32_t)ex6((c >> 5) & 0x3F) << 16) |
|
||||||
|
((uint32_t)ex5(c & 0x1F) << 8) | 0xFFu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirty_add(x1, y1, n, y2 - y1);
|
||||||
|
}
|
||||||
|
|
||||||
/* ================= present / 上屏 ================= */
|
/* ================= present / 上屏 ================= */
|
||||||
static void dump_ppm(void)
|
static void dump_ppm(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* meow_ui_img.c — 图片层(B1.2)。基于 stb_image(单头文件、静态编入),
|
* meow_ui_img.c — 图片层(B1.2)。解码:M23 真缩解后端(meow_jpeg.c / meow_png_stream.c)
|
||||||
* 解 PNG/JPEG/BMP → RGBA,统一最近邻缩放/居中裁方。
|
* 优先,不支持/失败回退 stb_image(单头文件、静态编入);统一输出 RGBA,最近邻缩放/居中裁方。
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
#include "meow_ui_internal.h"
|
#include "meow_ui_internal.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
#include "meow_jpeg.h" /* M23 真缩解后端(内部头,不对外导出) */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.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」的最大档,
|
/* 追加(M12):预算解码。选整数缩解档位 s ∈ {1,2,4,8}——取满足「长边/s ≥ maxdim」的最大档,
|
||||||
* 保证缩解结果不欠采样(不丢细节),再由 meow_img_downscale 精修到 maxdim。长边 < 2*maxdim
|
* 保证缩解结果不欠采样(不丢细节),再由 meow_img_downscale 精修到 maxdim。长边 < 2*maxdim
|
||||||
* 时无档可用(s=1),退回整幅解码后精修——此时本就接近目标尺寸,无需牺牲。 */
|
* 时无档可用(s=1),退回整幅解码后精修——此时本就接近目标尺寸,无需牺牲。 */
|
||||||
static int img_pick_scale(int longside, int maxdim)
|
int meow_img_pick_scale(int longside, int maxdim)
|
||||||
{
|
{
|
||||||
int s = 1;
|
int s = 1;
|
||||||
while (s < 8 && (longside / (s * 2)) >= maxdim) s *= 2;
|
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 (!path) return NULL;
|
||||||
if (maxdim <= 0) return meow_img_load_file(path); /* 不限尺寸 = 旧入口 */
|
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;
|
int w = 0, h = 0, c = 0;
|
||||||
if (!stbi_info(path, &w, &h, &c)) return NULL;
|
if (!stbi_info(path, &w, &h, &c)) return NULL;
|
||||||
int longside = w > h ? w : h;
|
int longside = w > h ? w : h;
|
||||||
if (longside <= maxdim) return meow_img_load_file(path); /* 小图不动:旧路径 */
|
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);
|
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)
|
meow_img *meow_img_load_mem_dim(const void *buf, int len, int maxdim)
|
||||||
{
|
{
|
||||||
if (!buf || len <= 0) return NULL;
|
if (!buf || len <= 0) return NULL;
|
||||||
if (maxdim <= 0) return meow_img_load_mem(buf, len);
|
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;
|
int w = 0, h = 0, c = 0;
|
||||||
if (!stbi_info_from_memory((const unsigned char *)buf, len, &w, &h, &c)) return NULL;
|
if (!stbi_info_from_memory((const unsigned char *)buf, len, &w, &h, &c)) return NULL;
|
||||||
int longside = w > h ? w : h;
|
int longside = w > h ? w : h;
|
||||||
if (longside <= maxdim) return meow_img_load_mem(buf, len);
|
if (longside <= maxdim) return meow_img_load_mem(buf, len);
|
||||||
unsigned char *p = stbi_load_scaled_from_memory((const unsigned char *)buf, len,
|
unsigned char *p = stbi_load_scaled_from_memory((const unsigned char *)buf, len,
|
||||||
&w, &h, &c, 4,
|
&w, &h, &c, 4,
|
||||||
img_pick_scale(longside, maxdim));
|
meow_img_pick_scale(longside, maxdim));
|
||||||
return img_finish_dim(p, w, h, maxdim);
|
return img_finish_dim(p, w, h, maxdim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
* gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \
|
* gcc -Wall -Wextra -o test_ime_fix test_ime_fix.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* meow_ui_anim.c meow_ui_media.c meow_ui_nav.c meow_pinyin.c meow_ui_box.c meow_ui_scroll.c \
|
* meow_ui_anim.c meow_ui_media.c meow_ui_nav.c meow_pinyin.c meow_ui_box.c meow_ui_scroll.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* (meow_ui_widget.c 新 W_LISTVIEW 引用 meow_ui_img_scaled → 需链 meow_ui_img.c+stb_image.c+-lm;
|
* (meow_ui_widget.c 新 W_LISTVIEW 引用 meow_ui_img_scaled → 需链 meow_ui_img.c+stb_image.c+-lm -lz;
|
||||||
* widget/input/ime/view 后续又引入 anim/media/nav/pinyin/box/scroll 依赖,一并链接)
|
* widget/input/ime/view 后续又引入 anim/media/nav/pinyin/box/scroll 依赖,一并链接)
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -10,13 +10,15 @@
|
|||||||
* B6 进升级:progressive JPEG 走同一缩解路径(峰值记录 + 长边约束)
|
* B6 进升级:progressive JPEG 走同一缩解路径(峰值记录 + 长边约束)
|
||||||
* B7 内存入口:meow_img_load_mem_dim 与文件入口等价(峰值 < 旧内存入口 1/2)
|
* B7 内存入口:meow_img_load_mem_dim 与文件入口等价(峰值 < 旧内存入口 1/2)
|
||||||
* B8 坏图:坏 JPEG(魔数+垃圾)/ 空内存 / 不存在路径 → NULL(不崩)
|
* B8 坏图:坏 JPEG(魔数+垃圾)/ 空内存 / 不存在路径 → NULL(不崩)
|
||||||
* B9 PNG/BMP:尺寸约束成立,峰值如实记录(stb 无解码期缩放 → 与旧入口同级)
|
* B9 PNG/BMP:尺寸约束成立;M23 起 PNG/BMP 也走解码期缩解(逐行 inflate / 按行 seek),
|
||||||
|
* 峰值应显著低于旧入口(本用例只断言 ≤ maxdim + 非空,并打印峰值供报告引用)
|
||||||
*
|
*
|
||||||
* 夹具(生成一次):
|
* 夹具(生成一次):
|
||||||
* python3 test_meow_img_budget_gen.py "$PREFIX/tmp/meow_img_budget"
|
* python3 test_meow_img_budget_gen.py "$PREFIX/tmp/meow_img_budget"
|
||||||
* 编译(本 sdk 目录下;--wrap 用于给 malloc/free 家族打点):
|
* 编译(本 sdk 目录下;--wrap 用于给 malloc/free 家族打点;-lz 供 PNG 后端 inflate):
|
||||||
* gcc -Wall -Wextra -I. -Iinclude -DMEOW_UI_HOST_TEST -o test_meow_img_budget \
|
* gcc -Wall -Wextra -I. -Iinclude -DMEOW_UI_HOST_TEST -o test_meow_img_budget \
|
||||||
* test_meow_img_budget.c meow_ui_img.c stb_image.c -lm \
|
* test_meow_img_budget.c meow_ui_img.c meow_jpeg.c meow_png_stream.c stb_image.c \
|
||||||
|
* -lm -lz \
|
||||||
* -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=realloc -Wl,--wrap=free
|
* -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=realloc -Wl,--wrap=free
|
||||||
* 运行:./test_meow_img_budget "$PREFIX/tmp/meow_img_budget" (exit 0=PASS / 1=FAIL)
|
* 运行:./test_meow_img_budget "$PREFIX/tmp/meow_img_budget" (exit 0=PASS / 1=FAIL)
|
||||||
* 夹具目录可省略:默认 $PREFIX/tmp/meow_img_budget;缺失时自动调 gen 脚本生成。
|
* 夹具目录可省略:默认 $PREFIX/tmp/meow_img_budget;缺失时自动调 gen 脚本生成。
|
||||||
@@ -421,8 +423,8 @@ int main(int argc, char **argv)
|
|||||||
CHECK(meow_img_load_mem_dim("x", 3, 480) == NULL, "垃圾内存 → NULL");
|
CHECK(meow_img_load_mem_dim("x", 3, 480) == NULL, "垃圾内存 → NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- B9 PNG / BMP(stb 无解码期缩放,如实记录峰值) ---- */
|
/* ---- B9 PNG / BMP(M23 起也走解码期缩解;只断言尺寸/非空,峰值打印) ---- */
|
||||||
printf("[B9] PNG / BMP:尺寸约束成立,峰值如实记录(stb 无解码期缩放)\n");
|
printf("[B9] PNG / BMP:尺寸约束成立,峰值记录(M23 逐行/跳行缩解,应远低于旧入口)\n");
|
||||||
{
|
{
|
||||||
struct { const char *tag; const char *path; } fx[] = {
|
struct { const char *tag; const char *path; } fx[] = {
|
||||||
{ "PNG", p_png }, { "BMP", p_bmp },
|
{ "PNG", p_png }, { "BMP", p_bmp },
|
||||||
@@ -446,8 +448,8 @@ int main(int argc, char **argv)
|
|||||||
CHECK(nw && meow_img_w(nw) <= 480 && meow_img_h(nw) <= 480 && nonblank(nw), name);
|
CHECK(nw && meow_img_w(nw) <= 480 && meow_img_h(nw) <= 480 && nonblank(nw), name);
|
||||||
peak_report(fx[i].tag, p_old);
|
peak_report(fx[i].tag, p_old);
|
||||||
peak_report(" ↑ 新入口", p_new);
|
peak_report(" ↑ 新入口", p_new);
|
||||||
snprintf(name, sizeof name, "%s 峰值与旧入口同级(stb 无解码期缩放)", fx[i].tag);
|
snprintf(name, sizeof name, "%s 新入口峰值 ≤ 旧入口(不再整幅物化)", fx[i].tag);
|
||||||
CHECK(p_new <= p_old + p_old / 8, name);
|
CHECK(p_new <= p_old, name);
|
||||||
if (old) printf(" %s 原图 %dx%d\n", fx[i].tag, meow_img_w(old), meow_img_h(old));
|
if (old) printf(" %s 原图 %dx%d\n", fx[i].tag, meow_img_w(old), meow_img_h(old));
|
||||||
meow_img_free(nw);
|
meow_img_free(nw);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_img_color
|
* 运行:./test_meow_img_color
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -8,8 +8,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_lyric_view
|
* 运行:./test_meow_lyric_view
|
||||||
*
|
*
|
||||||
* 覆盖矩阵(对齐任务批2:活动行纯白/灰阶、翻译行占位不叠行、偏上锚定、折行中西文、点行 seek 命中、
|
* 覆盖矩阵(对齐任务批2:活动行纯白/灰阶、翻译行占位不叠行、偏上锚定、折行中西文、点行 seek 命中、
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_md3
|
* 运行:./test_meow_md3
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_anim
|
* 运行:./test_meow_ui_anim
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_box
|
* 运行:./test_meow_ui_box
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_dispatch (无设备,纯宿主)
|
* 运行:./test_meow_ui_dispatch (无设备,纯宿主)
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_home_gesture
|
* 运行:./test_meow_ui_home_gesture
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_iconbtn
|
* 运行:./test_meow_ui_iconbtn
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_lazygrid.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_lazygrid.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_lazygrid
|
* 运行:./test_meow_ui_lazygrid
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_ui_nav.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c meow_ui_nav.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm \
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz \
|
||||||
* -Wl,--wrap=meow_ui_text_height
|
* -Wl,--wrap=meow_ui_text_height
|
||||||
* 运行:./test_meow_ui_listview_rowh
|
* 运行:./test_meow_ui_listview_rowh
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_listvirt
|
* 运行:./test_meow_ui_listvirt
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_ui_nav.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c meow_ui_nav.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_scroll
|
* 运行:./test_meow_ui_scroll
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_select.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_select.c meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_select
|
* 运行:./test_meow_ui_select
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_swipe
|
* 运行:./test_meow_ui_swipe
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
* gcc -o test_meow_ui_theme test_meow_ui_theme.c test_host_stub.c \
|
* gcc -o test_meow_ui_theme test_meow_ui_theme.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
*
|
*
|
||||||
* 验证要点:四套主题 primary/radius 各不相同(MD3 蓝 / MIUIx 橙 + 更大圆角),
|
* 验证要点:四套主题 primary/radius 各不相同(MD3 蓝 / MIUIx 橙 + 更大圆角),
|
||||||
* 同 style 下 light/dark 的 surface 成对切换;图形用 MEOW_UI_DUMP 导出 PPM 目检。
|
* 同 style 下 light/dark 的 surface 成对切换;图形用 MEOW_UI_DUMP 导出 PPM 目检。
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_theme_export
|
* 运行:./test_meow_ui_theme_export
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_box.c meow_ui_anim.c meow_ui_scroll.c \
|
||||||
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_img.c meow_ui_media.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:./test_meow_ui_view_event
|
* 运行:./test_meow_ui_view_event
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
* gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \
|
* gcc -o test_meow_ui_widgets test_meow_ui_widgets.c test_host_stub.c \
|
||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c \
|
* meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
* 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕)
|
* 运行:MEOW_UI_DUMP=/tmp/b2.ppm ./test_meow_ui_widgets (可选,dump 屏幕)
|
||||||
*
|
*
|
||||||
* 注:W_LISTVIEW 的 MEOW_LIST_ICON_IMG 分支调用 meow_ui_img_scaled → 宿主链 meow_ui_img.c+stb_image.c+-lm。
|
* 注:W_LISTVIEW 的 MEOW_LIST_ICON_IMG 分支调用 meow_ui_img_scaled → 宿主链 meow_ui_img.c+stb_image.c+-lm -lz。
|
||||||
* 结构化列表断言用 back_buf 像素(region_has/px_near),画完即读,非目检。
|
* 结构化列表断言用 back_buf 像素(region_has/px_near),画完即读,非目检。
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
|
|||||||
@@ -25,11 +25,11 @@
|
|||||||
* test_host_stub.c meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* test_host_stub.c meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \
|
* meow_ui_img.c meow_ui_config.c meow_ui_notify.c meow_notify_ipc.c meow_ui_draw.c \
|
||||||
* meow_ui_view.c meow_ui_nav.c meow_ui_media.c stb_image.c \
|
* meow_ui_view.c meow_ui_nav.c meow_ui_media.c stb_image.c meow_jpeg.c meow_png_stream.c \
|
||||||
* ../hello_app/ui/home/home.c ../hello_app/ui/full.c ../hello_app/ui/demo/demo.c \
|
* ../hello_app/ui/home/home.c ../hello_app/ui/full.c ../hello_app/ui/demo/demo.c \
|
||||||
* ../hello_app/ui/demo/list/list.c ../hello_app/ui/common/chrome.c \
|
* ../hello_app/ui/demo/list/list.c ../hello_app/ui/common/chrome.c \
|
||||||
* ../hello_app/logic/notify.c ../hello_app/logic/state.c \
|
* ../hello_app/logic/notify.c ../hello_app/logic/state.c \
|
||||||
* -I. -I../hello_app -I../meow_launcherd -pthread -lm
|
* -I. -I../hello_app -I../meow_launcherd -pthread -lm -lz
|
||||||
* 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕)
|
* 运行:MEOW_UI_DUMP=/tmp/repro.ppm ./test_p1p2p3_repro (optional,dump 最终屏幕)
|
||||||
*
|
*
|
||||||
* 预期 RESULT: ALL PASS(P1c/P2/P3 断言真实有效,未弱化)。
|
* 预期 RESULT: ALL PASS(P1c/P2/P3 断言真实有效,未弱化)。
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c \
|
||||||
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
* meow_ui_widget.c meow_ui_input.c meow_ui_activity.c meow_ui_dialog.c meow_ui_ime.c meow_ui_str.c \
|
||||||
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_ui_media.c \
|
* meow_pinyin.c meow_ui_draw.c meow_ui_view.c meow_ui_img.c meow_ui_media.c \
|
||||||
* meow_notify_ipc.c stb_image.c -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm
|
* meow_notify_ipc.c stb_image.c meow_jpeg.c meow_png_stream.c -I. -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread -lm -lz
|
||||||
*/
|
*/
|
||||||
#include "meow_ui.h"
|
#include "meow_ui.h"
|
||||||
#include "meow_ui_internal.h"
|
#include "meow_ui_internal.h"
|
||||||
|
|||||||
Reference in new issue
Block a user