/* * 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 #include #include 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; float ox = 0.0f, oy = 0.0f; if (cover) { float sx = (float)im->w / dw, sy = (float)im->h / dh; s = sx > sy ? sx : sy; /* 铺满 → 可能外溢,居中裁 */ float sw = im->w / s, sh = im->h / s; /* 目标显示寸(sw×sh) */ ox = (float)(dw - sw) * 0.5f; oy = (float)(dh - sh) * 0.5f; if (ox < 0) ox = 0; if (oy < 0) oy = 0; for (int dy = 0; dy < dh; dy++) { int syi = (int)((dy + oy) / s); if (syi < 0) syi = 0; if (syi >= im->h) syi = im->h - 1; for (int dx = 0; dx < dw; dx++) { int sxi = (int)((dx + ox) / s); 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; } 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); }