Chapter 73 · SVG 引擎

SVG 加载与缓存

XGE 内置 SVG 解析器,支持文件/内存加载、引用计数管理和全局缓存,避免重复解析。

73

API 速查

函数说明
int xgeSvgCreate(xge_svg* ppSvg)创建空 SVG 对象
void xgeSvgDestroy(xge_svg pSvg)销毁(Release)
int xgeSvgAddRef(xge_svg pSvg)增加引用
int xgeSvgLoad(xge_svg pSvg, const char* sURI)从文件加载
int xgeSvgLoadMemory(xge_svg pSvg, const void* pData, int iSize)从内存加载
int xgeSvgLoadCached(const char* sURI, xge_svg* ppSvg)缓存加载(共享)
int xgeSvgClear(xge_svg pSvg)清空内容
int xgeSvgClone(xge_svg pSvg, xge_svg* ppClone)深拷贝
int xgeSvgCacheInvalidate(const char* sURI)使缓存失效
void xgeSvgCacheClear(void)清空全局缓存

编译本章示例

gcc -O2 -I. -o ch73.exe ch73_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch73.exe

示例:加载与缓存

// 方式 1:从文件加载(独立实例)
xge_svg svg = NULL;
xgeSvgCreate(&svg);
xgeSvgLoad(svg, "assets/icon.svg");

// 方式 2:从内存加载
const char* svgData = "<svg>...</svg>";
xgeSvgLoadMemory(svg, svgData, (int)strlen(svgData));

// 方式 3:缓存加载(多处共享同一实例)
xge_svg shared = NULL;
xgeSvgLoadCached("assets/logo.svg", &shared);
// 再次调用返回同一对象(引用 +1)
xge_svg shared2 = NULL;
xgeSvgLoadCached("assets/logo.svg", &shared2);

// 文件修改后刷新缓存
xgeSvgCacheInvalidate("assets/logo.svg");

// 释放
xgeSvgDestroy(svg);
xgeSvgDestroy(shared);
xgeSvgDestroy(shared2);

完整代码

将以下代码保存为 ch73_main.c,编译后运行即可看到 SVG 加载与缓存绘制效果(需准备 assets/icon.svg 文件):

#include "xge.h"

static xge_svg g_svg = NULL;
static xge_svg g_cached = NULL;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);

    // 绘制独立实例
    xgeSvgSetOrigin(g_svg, 100.0f, 150.0f);
    xgeSvgSetSize(g_svg, 120.0f, 120.0f);
    xgeSvgDraw(g_svg, 0.25f);

    // 绘制缓存实例(不同位置/尺寸)
    xgeSvgSetOrigin(g_cached, 400.0f, 150.0f);
    xgeSvgSetSize(g_cached, 200.0f, 200.0f);
    xgeSvgDraw(g_cached, 0.25f);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch73 - SVG Load & Cache";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    // 方式 1:独立加载
    xgeSvgCreate(&g_svg);
    xgeSvgLoad(g_svg, "assets/icon.svg");

    // 方式 2:缓存加载(共享实例)
    xgeSvgLoadCached("assets/icon.svg", &g_cached);

    xgeRun(onFrame, NULL);
    xgeSvgDestroy(g_svg);
    xgeSvgDestroy(g_cached);
    xgeSvgCacheClear();
    xgeUnit();
    return 0;
}

代码讲解

  • 独立加载:xgeSvgCreate + xgeSvgLoad 创建独立实例,可自由修改不影响他人。
  • 缓存加载:xgeSvgLoadCached 返回全局共享实例,多次调用同一 URI 返回相同指针(引用+1)。
  • SetSize/SetOrigin:同一 SVG 可以不同尺寸/位置绘制,展示矢量图无损缩放。
  • CacheClear:退出前清空全局缓存,释放内存。

要点与陷阱

  • LoadCached 共享:返回同一指针,修改会影响所有使用者;需要独立副本用 Clone。
  • 引用计数:LoadCached 自动 AddRef,每次 Destroy 减一,归零才真正释放。
  • Load 覆盖:对已有内容的 SVG 调用 Load 会先 Clear 再解析。
  • cacheClear:清空所有缓存条目,适合资源热重载场景。

进阶练习

  1. 实现 SVG 资源管理器:预加载 + 引用计数 + 自动释放。
  2. 文件监控:检测到 .svg 修改后 Invalidate + 重新加载。
SVG 加载与缓存效果
图:SVG 加载与缓存渲染效果