/* * svg_doc.cpp * SvgDoc: source-backed rasterizable SVG document. * Copyright (c) 2026 Daniel Hammer */ #include "svg_doc.hpp" #include #include #include #include namespace imageviewer { bool svgdoc_init(SvgDoc* doc, uint8_t* source, int source_len) { if (!doc) return false; *doc = {}; if (!source || source_len <= 0) return false; doc->source = source; doc->source_len = source_len; gui::svg_get_natural_size((const char*)source, source_len, &doc->natural_w, &doc->natural_h); if (doc->natural_w < 1) doc->natural_w = 1; if (doc->natural_h < 1) doc->natural_h = 1; return true; } bool svgdoc_render(SvgDoc* doc, float target_scale, int max_edge) { if (!doc || !doc->source) return false; if (target_scale <= 0.0f) target_scale = 1.0f; if (max_edge < 1) max_edge = 1; // Clamp so the longest edge of the rasterized output stays within max_edge. int natural_long = doc->natural_w > doc->natural_h ? doc->natural_w : doc->natural_h; float max_scale = (float)max_edge / (float)natural_long; if (target_scale > max_scale) target_scale = max_scale; if (target_scale < 0.01f) target_scale = 0.01f; // Skip if cache is already close enough (avoids re-render on float jitter). if (doc->pixels && doc->render_scale > 0.0f) { float ratio = target_scale / doc->render_scale; if (ratio > 0.995f && ratio < 1.005f) return true; } int new_w = (int)((float)doc->natural_w * target_scale); int new_h = (int)((float)doc->natural_h * target_scale); if (new_w < 1) new_w = 1; if (new_h < 1) new_h = 1; gui::SvgIcon icon = gui::svg_render( (const char*)doc->source, doc->source_len, new_w, new_h, gui::Color::from_rgb(0, 0, 0)); if (!icon.pixels) return false; if (doc->pixels) montauk::mfree(doc->pixels); doc->pixels = icon.pixels; doc->render_w = icon.width; doc->render_h = icon.height; doc->render_scale = target_scale; return true; } void svgdoc_free(SvgDoc* doc) { if (!doc) return; if (doc->pixels) montauk::mfree(doc->pixels); if (doc->source) montauk::mfree(doc->source); *doc = {}; } } // namespace imageviewer