Files
MeowOS-SDK/sdk/meow_ui_img.c
T
AskaEth 4b094d62a5 sdk: 增量同步主仓新模块(box/anim/scroll/dispatch/listvirt/str/sb_icons/img)
subtree pull sdk 来自主仓 pub/sdk(主仓 commit 68ce46a 等)。新增:
- 布局引擎 meow_ui_box / 动画基座 meow_ui_anim / 滚动物理 meow_ui_scroll
- §6.4 事件分发形式化 / W_LISTVIEW 虚拟化多行 / meow_str 字符串资源 i18n
- sb_icons 动作图标扩充 + topbar 位图图标 / meow_img_downscale
- tools/ 图标生成脚本与 SVG 源
- 对应宿主 test_*.c 与 demo_box_scroll.c

build_sdk.sh 冲突解析:保留公开仓自包含版(vendored meow_font + -Iinclude -I.),
OBJS 手工并入 4 个新模块(meow_ui_box/anim/scroll/str)。保留 vendored meow_font.c/
meow_ipc.h/meow_font.h/meow_notif.h,剔除宿主测试二进制与编译产物。
2026-09-02 09:08:51 +08:00

155 lines
5.6 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_img.c — 图片层(B1.2)。基于 stb_image(单头文件、静态编入),
* 解 PNG/JPEG/BMP → RGBA,统一最近邻缩放/居中裁方。
*/
#include "meow_ui.h"
#include "meow_ui_internal.h"
#include "stb_image.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct meow_img {
int w, h;
unsigned char *rgba; /* 4 通道 straight alpha */
};
static meow_img *img_alloc(int w, int h, unsigned char *rgba)
{
if (w <= 0 || h <= 0 || !rgba) { if (rgba) stbi_image_free(rgba); return NULL; }
meow_img *im = (meow_img *)malloc(sizeof *im);
if (!im) { stbi_image_free(rgba); return NULL; }
im->w = w; im->h = h; im->rgba = rgba;
return im;
}
meow_img *meow_img_load_mem(const void *buf, int len)
{
if (!buf || len <= 0) return NULL;
int w = 0, h = 0, c = 0;
unsigned char *p = stbi_load_from_memory((const unsigned char *)buf, len, &w, &h, &c, 4);
if (!p) return NULL;
return img_alloc(w, h, p);
}
meow_img *meow_img_load_file(const char *path)
{
if (!path) return NULL;
int w = 0, h = 0, c = 0;
unsigned char *p = stbi_load(path, &w, &h, &c, 4);
if (!p) return NULL;
return img_alloc(w, h, p);
}
void meow_img_free(meow_img *im)
{
if (!im) return;
if (im->rgba) stbi_image_free(im->rgba);
free(im);
}
int meow_img_w(meow_img *im) { return im ? im->w : 0; }
int meow_img_h(meow_img *im) { return im ? im->h : 0; }
/* 最近邻采样缩放(cover=1 居中裁方),返回 dw*dh*4 临时 RGBA 缓冲 */
static unsigned char *scale_buf(const meow_img *im, int dw, int dh, int cover)
{
if (!im || dw <= 0 || dh <= 0) return NULL;
unsigned char *out = (unsigned char *)malloc((size_t)dw * dh * 4);
if (!out) return NULL;
float s = 1.0f;
if (cover) {
/* 真正铺满(cover):每目标像素对应 s 个源像素,s = min(W/dw, H/dh)——缩放后图像
* 宽/高两维都不小于目标(可能外溢),居中裁方。居中裁剪偏移(源像素)= (W-dw*s)/2
* 恒 ≥ 0。曾误作 `s = max(sx,sy)` 且采样 `(dx+ox)/s`(除以缩放比):把整块输出映射到
* 源左上角 ~dw/s 像素的透明角——图标(透明角 logo)整块透明、不绘制,即
* 「icon: ... OK 但渲染不出(只显首字母占位)」根因。正确:源索引 = dx*s + 裁剪偏移
* (与下方非 cover 分支 `dx*im->w/dw` 同一乘向)。 */
float sx = (float)im->w / dw, sy = (float)im->h / dh;
s = sx < sy ? sx : sy; /* 源像素/目标像素(铺满 → 取小) */
float oxs = ((float)im->w - (float)dw * s) * 0.5f; /* 居中裁剪起点(源像素,≥0) */
float oys = ((float)im->h - (float)dh * s) * 0.5f;
if (oxs < 0) oxs = 0; if (oys < 0) oys = 0;
for (int dy = 0; dy < dh; dy++) {
int syi = (int)((float)dy * s + oys);
if (syi < 0) syi = 0; if (syi >= im->h) syi = im->h - 1;
for (int dx = 0; dx < dw; dx++) {
int sxi = (int)((float)dx * s + oxs);
if (sxi < 0) sxi = 0; if (sxi >= im->w) sxi = im->w - 1;
memcpy(out + ((size_t)dy * dw + dx) * 4,
im->rgba + ((size_t)syi * im->w + sxi) * 4, 4);
}
}
} else {
for (int dy = 0; dy < dh; dy++) {
int syi = (int)((float)dy * im->h / dh);
if (syi >= im->h) syi = im->h - 1;
for (int dx = 0; dx < dw; dx++) {
int sxi = (int)((float)dx * im->w / dw);
if (sxi >= im->w) sxi = im->w - 1;
memcpy(out + ((size_t)dy * dw + dx) * 4,
im->rgba + ((size_t)syi * im->w + sxi) * 4, 4);
}
}
}
return out;
}
/* 内存瘦身:把大图按最近邻等比缩放到「最长边 ≤ maxdim」,返回新图;调用方负责
* meow_img_free 旧图 + 新图。原图已 ≤maxdim → 返回 NULL(无需缩放)。
* 典型:网易云全尺寸封面 1448×1448 RGBA=8MB,显示只需 ≤480px(屏幕 480 宽)→
* 480×480=0.9MB,省 ~7MB anon(设备 RAM 仅 56MB,OOM 真机被杀)。
* 复用 scale_buf(cover=0,最近邻锁比例),不做插值(App 封面/背景无需高质量缩放)。 */
meow_img *meow_img_downscale(meow_img *im, int maxdim)
{
if (!im || maxdim <= 0) return NULL;
if (im->w <= maxdim && im->h <= maxdim) return NULL; /* 已够小,不缩放 */
int dw, dh;
if (im->w >= im->h) {
dw = maxdim;
dh = (int)((long)im->h * maxdim / im->w);
} else {
dh = maxdim;
dw = (int)((long)im->w * maxdim / im->h);
}
if (dw < 1) dw = 1;
if (dh < 1) dh = 1;
unsigned char *tmp = scale_buf(im, dw, dh, 0);
if (!tmp) return NULL;
return img_alloc(dw, dh, tmp);
}
void meow_ui_img(int x, int y, meow_img *im)
{
if (!im) return;
meow_gfx_blit_rgba(x, y, im->w, im->h, im->rgba, 255);
}
void meow_ui_img_scaled(int x, int y, int w, int h, meow_img *im)
{
if (!im) return;
unsigned char *tmp = scale_buf(im, w, h, 0);
if (!tmp) return;
meow_gfx_blit_rgba(x, y, w, h, tmp, 255);
free(tmp);
}
void meow_ui_img_alpha(int x, int y, int w, int h, meow_img *im, int alpha)
{
if (!im) return;
unsigned char *tmp = scale_buf(im, w, h, 0);
if (!tmp) return;
meow_gfx_blit_rgba(x, y, w, h, tmp, alpha);
free(tmp);
}
void meow_ui_img_cover(int x, int y, int size, meow_img *im)
{
if (!im) return;
unsigned char *tmp = scale_buf(im, size, size, 1);
if (!tmp) return;
meow_gfx_blit_rgba(x, y, size, size, tmp, 255);
free(tmp);
}