feat: SVG support in Image viewer app

This commit is contained in:
2026-05-18 20:07:37 +02:00
parent 47e3bb54a5
commit 6ac9ae01b0
3 changed files with 93 additions and 1 deletions
@@ -45,7 +45,9 @@ bool str_ends_with(const char* s, const char* suffix) {
}
bool is_image_file(const char* name) {
return str_ends_with(name, ".jpg") || str_ends_with(name, ".jpeg");
return str_ends_with(name, ".jpg")
|| str_ends_with(name, ".jpeg")
|| str_ends_with(name, ".svg");
}
bool is_font_file(const char* name) {
+50
View File
@@ -10,6 +10,7 @@
#include <gui/gui.hpp>
#include <gui/standalone.hpp>
#include <gui/truetype.hpp>
#include <gui/svg.hpp>
extern "C" {
#include <string.h>
@@ -99,6 +100,20 @@ static const char* basename(const char* path) {
return last;
}
static bool path_has_ext_ci(const char* path, const char* ext) {
int pl = 0; while (path[pl]) pl++;
int el = 0; while (ext[el]) el++;
if (pl < el) return false;
for (int i = 0; i < el; i++) {
char a = path[pl - el + i];
char b = ext[i];
if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a');
if (b >= 'A' && b <= 'Z') b = (char)(b - 'A' + 'a');
if (a != b) return false;
}
return true;
}
// ============================================================================
// Image loading
// ============================================================================
@@ -135,6 +150,41 @@ static bool load_image(const char* path) {
return false;
}
// SVG: vector path through our own rasterizer. stb_image can't decode SVG.
if (path_has_ext_ci(path, ".svg")) {
int nat_w = 0, nat_h = 0;
svg_get_natural_size((const char*)filedata, bytes_read, &nat_w, &nat_h);
// Cap longest edge to keep memory bounded (4 bytes/pixel).
constexpr int MAX_EDGE = 2048;
int max_edge = nat_w > nat_h ? nat_w : nat_h;
if (max_edge > MAX_EDGE) {
nat_w = (int)((int64_t)nat_w * MAX_EDGE / max_edge);
nat_h = (int)((int64_t)nat_h * MAX_EDGE / max_edge);
}
if (nat_w < 1) nat_w = 1;
if (nat_h < 1) nat_h = 1;
// fill_color is the currentColor substitute. Real SVG files mostly
// specify their own fills, so this only matters for paths that use
// currentColor; default to black for sensible fallback.
SvgIcon icon = svg_render((const char*)filedata, bytes_read,
nat_w, nat_h, Color::from_rgb(0, 0, 0));
montauk::mfree(filedata);
if (!icon.pixels) {
montauk::strcpy(g_status, "Error: SVG render failed");
return false;
}
g_image = icon.pixels;
g_img_w = icon.width;
g_img_h = icon.height;
g_has_alpha = true;
snprintf(g_status, 256, "%s %dx%d SVG", basename(path), g_img_w, g_img_h);
return true;
}
int w, h, channels;
unsigned char* rgba = stbi_load_from_memory(filedata, bytes_read, &w, &h, &channels, 4);
montauk::mfree(filedata);