sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓

sdk/:
- 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头
  (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退;
   全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势;
   LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定;
   DSD 音频格式等)
- 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c
- 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动;
  build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径;
  meow_ui_internal.h 去除 FreeType 内部声明
- meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议)
- 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font
  自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs

examples/hello/:
- 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含)

docs / README / .gitignore:
- docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API)
- README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」
- .gitignore 补新增宿主测试二进制

验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
This commit is contained in:
AskaEth committed 2026-09-04 18:05:36 +08:00
1 parent a1687486bc
commit c0396e40ce
45 files changed
+4665 -175

No files matched your search

+151
View File
@@ -0,0 +1,151 @@
/*
* meow_img_color.c — MeowOS SDK 封面双色渐变取色实现(见 meow_img_color.h 契约)。
*
* 独立源码,不并入 meow_ui.a(铁律:避免并发重编/四 App 重链)。取色算法纯函数(无 GPU/浮点/堆)。
* 唯一 meow_* 依赖:仅 meow_img_pixels(SDK 正式访问器,meow_ui_img.c §4),并经 meow_img_w/h 取宽高
* ——三者读 meow_img 的唯一入口,本 TU 不再局部补全其结构体(agent-402 遗留点已上收)。App/宿主
* 链入 meow_img_color.c 时需能解析 meow_img_pixels/w/h(宿主测试已链 meow_ui_img.c,实际 App 恒链
* meow_ui.a)。
*/
#include "meow_img_color.h"
#include <string.h>
#define MIC_BUCKETS 4 /* 每通道色阶数 ⇒ 4×4×4=64 桶 */
#define MIC_NBUCKET (MIC_BUCKETS*MIC_BUCKETS*MIC_BUCKETS)
#define MIC_ALPHA_MIN 64 /* 跳过近透明(alpha<64) */
#define MIC_LUMA_MIN 24 /* 跳过近黑 */
#define MIC_LUMA_MAX 244 /* 跳过近白 */
#define MIC_MIN_VALID 8 /* 有效采样下限(低于=取色失败回退主题) */
#define MIC_TARGET 900 /* 目标采样数(副采样步进自适,×4 作上限) */
#define MIC_SEC_FRAC 7U /* 次桶显著门槛:≥主桶 1/7(≈14%) */
static int mic_luma(uint32_t c)
{
int r = (int)((c >> 16) & 255), g = (int)((c >> 8) & 255), b = (int)(c & 255);
return (r * 299 + g * 587 + b * 114) / 1000;
}
/* 两色线性混合(t=0..255,0=纯 a、255=纯 b;逐通道整数,无浮点)。 */
static uint32_t mic_mix(uint32_t a, uint32_t b, int t)
{
if (t < 0) t = 0;
if (t > 255) t = 255;
int ar = (a >> 16) & 255, ag = (a >> 8) & 255, ab = a & 255;
int br = (b >> 16) & 255, bg = (b >> 8) & 255, bb = b & 255;
int r = ar + ((br - ar) * t + 128) / 255;
int g = ag + ((bg - ag) * t + 128) / 255;
int bl = ab + ((bb - ab) * t + 128) / 255;
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)bl;
}
int meow_img_duocolor_rgba(const uint8_t *rgba, int w, int h,
uint32_t *main, uint32_t *second)
{
if (!rgba || w <= 0 || h <= 0 || !main || !second) return -1;
/* 副采样步进:使采样数≈MIC_TARGET(×4 上限),大图/缩略图成本恒定。 */
int step = 1;
while ((long)(w / step) * (long)(h / step) > (long)MIC_TARGET * 4 && step < 64)
step++;
long cnt[MIC_NBUCKET];
long sr[MIC_NBUCKET], sg[MIC_NBUCKET], sb[MIC_NBUCKET], sw[MIC_NBUCKET];
memset(cnt, 0, sizeof cnt);
memset(sr, 0, sizeof sr);
memset(sg, 0, sizeof sg);
memset(sb, 0, sizeof sb);
memset(sw, 0, sizeof sw);
long total = 0;
for (int y = 0; y < h; y += step) {
for (int x = 0; x < w; x += step) {
const uint8_t *p = rgba + ((size_t)y * (size_t)w + (size_t)x) * 4;
int a = p[3];
if (a < MIC_ALPHA_MIN) continue;
int r = p[0], g = p[1], b = p[2];
if ((r * 299 + g * 587 + b * 114) / 1000 < MIC_LUMA_MIN) continue; /* 近黑 */
if ((r * 299 + g * 587 + b * 114) / 1000 > MIC_LUMA_MAX) continue; /* 近白 */
int mx = r, mn = r;
if (g > mx) mx = g;
if (b > mx) mx = b;
if (g < mn) mn = g;
if (b < mn) mn = b;
int sat = mx - mn; /* 饱和度 0..255 */
long wt = 1 + sat / 24; /* 1..~11:偏向鲜艳(跳过灰蒙蒙) */
int qr = r * MIC_BUCKETS / 256, qg = g * MIC_BUCKETS / 256, qb = b * MIC_BUCKETS / 256;
int bi = (qr * MIC_BUCKETS + qg) * MIC_BUCKETS + qb;
if (bi < 0 || bi >= MIC_NBUCKET) continue;
cnt[bi] += wt;
sr[bi] += (long)r * wt; sg[bi] += (long)g * wt; sb[bi] += (long)b * wt;
sw[bi] += wt;
total++;
}
}
if (total < MIC_MIN_VALID) return -1; /* 全透明/近黑白 → 失败回退主题 */
/* 主色:加权最大桶中心 */
int mi = -1;
long best = -1;
for (int i = 0; i < MIC_NBUCKET; i++)
if (cnt[i] > best) { best = cnt[i]; mi = i; }
if (mi < 0 || sw[mi] <= 0) return -1;
long mr0 = sr[mi] / sw[mi], mg0 = sg[mi] / sw[mi], mb0 = sb[mi] / sw[mi];
*main = ((uint32_t)mr0 << 16) | ((uint32_t)mg0 << 8) | (uint32_t)mb0;
/* 次色:与主色 RGB 色距最大的显著桶;无显著桶→主色缩暗 2/3(渐变互补)。 */
long thresh = best > 0 ? best / MIC_SEC_FRAC : 1;
int si = -1;
long sd = -1;
for (int i = 0; i < MIC_NBUCKET; i++) {
if (i == mi || cnt[i] < thresh || sw[i] <= 0) continue;
long dr = sr[i] / sw[i] - mr0, dg = sg[i] / sw[i] - mg0, db = sb[i] / sw[i] - mb0;
long d = dr * dr + dg * dg + db * db;
if (d > sd) { sd = d; si = i; }
}
if (si >= 0)
*second = ((uint32_t)(sr[si] / sw[si]) << 16) | ((uint32_t)(sg[si] / sw[si]) << 8) |
(uint32_t)(sb[si] / sw[si]);
else
*second = ((uint32_t)(mr0 * 2 / 3) << 16) | ((uint32_t)(mg0 * 2 / 3) << 8) |
(uint32_t)(mb0 * 2 / 3);
return 0;
}
int meow_img_duocolor(const meow_img *im, uint32_t *main, uint32_t *second)
{
if (!im) return -1;
/* 经 SDK 正式访问器读像素(meow_img opaque;meow_img_pixels 为唯一读入口)。 */
const unsigned char *rgba = meow_img_pixels(im);
if (!rgba) return -1;
return meow_img_duocolor_rgba(rgba, meow_img_w(im), meow_img_h(im), main, second);
}
void meow_img_color_derive(uint32_t main, uint32_t second, const meow_theme *th,
meow_img_color_theme *out)
{
if (!out) return;
uint32_t mainv = main ? main : (th ? th->primary : 0x808080);
uint32_t secv = second ? second : (th ? th->secondary : mainv);
/* 背景平均亮度 → 文字可读色(黑/白) */
int luavg = (mic_luma(mainv) + mic_luma(secv)) / 2;
uint32_t fg = (luavg >= 140) ? 0x1C1C1C : 0xFFFFFF;
uint32_t fgd = mic_mix(fg, mic_mix(mainv, 0x0A0A0A, 150), 90); /* 次要文字向背景靠(降对比) */
/* 背景渐变:主/次各压暗 55%(防刺眼 + 保文字可读) */
uint32_t bg_top = mic_mix(mainv, 0x0A0A0A, 150);
uint32_t bg_bottom = mic_mix(secv, 0x0A0A0A, 150);
/* 强调=次色(与主色底对比);其上图标按 accent 亮度选黑/白 */
uint32_t accent = secv;
uint32_t accent_fg = (mic_luma(accent) >= 140) ? 0x1C1C1C : 0xFFFFFF;
out->bg_top = bg_top; out->bg_bottom = bg_bottom;
out->fg = fg; out->fg_dim = fgd;
out->accent = accent; out->accent_fg = accent_fg;
/* 歌词页覆盖:scrim=主色压暗、cur=fg(可读)、gray 留 0(lyric_view 以 cur 自动递减)。 */
meow_lyric_view_colors *lc = &out->lyr;
memset(lc, 0, sizeof *lc);
lc->scrim = mic_mix(mainv, 0x000000, 150);
lc->cur = fg;
lc->scrim_alpha = 176;
}