Chapter 92 · 图像与纹理

图像保存

xgeImageSavePNG 将像素数据编码为 PNG 文件,常用于截图、离屏渲染导出和纹理回读。

92

概念

SavePNG 是引擎唯一的图像编码输出接口。它接收原始 RGBA 像素指针, 编码为无损 PNG 文件。常见用途:窗口截图、Render Target 回读保存、生成缩略图。

API 速查

函数说明
int xgeImageSavePNG(const char* sPath, int iWidth, int iHeight, const void* pPixels, int iStride)将 RGBA 像素保存为 PNG

编译本章示例

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

示例:窗口截图

// 获取窗口尺寸
int w = xgeGetWidth();
int h = xgeGetHeight();

// 分配像素缓冲区
int stride = w * 4;
uint8_t* pixels = (uint8_t*)malloc(stride * h);

// 从 Render Target 回读
xge_render_target_t rt;
xgeRenderTargetWindow(&rt);
xgeRenderTargetReadPixels(&rt, pixels, stride);

// 保存为 PNG
xgeImageSavePNG("screenshot.png", w, h, pixels, stride);

free(pixels);

完整代码

将以下代码保存为 ch92_main.c,编译后运行,按空格键截图保存为 PNG:

#include "xge.h"
#include <stdlib.h>
#include <stdio.h>

static xge_font g_font = NULL;
static int g_shotCount = 0;
static float g_time = 0.0f;

static void takeScreenshot(void) {
    int w = xgeGetWidth();
    int h = xgeGetHeight();
    int stride = w * 4;
    uint8_t* pixels = (uint8_t*)malloc(stride * h);
    if (!pixels) return;

    // 从窗口 Render Target 回读像素
    xge_render_target_t rt;
    xgeRenderTargetWindow(&rt);
    xgeRenderTargetReadPixels(&rt, pixels, stride);

    // 保存为 PNG
    char path[128];
    sprintf(path, "screenshot_%03d.png", g_shotCount++);
    xgeImageSavePNG(path, w, h, pixels, stride);
    free(pixels);
}

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);
    g_time += 0.016f;

    // 绘制动态场景(截图内容)
    float cx = 400.0f + 150.0f * cosf(g_time);
    float cy = 300.0f + 100.0f * sinf(g_time);
    xgeShapeCircleFill(cx, cy, 30.0f, 0xFF8844FF);
    xgeShapeRectStroke((xge_rect_t){100, 100, 200, 150}, 2.0f, 0x4488CCFF)

    // 提示文字
    xgeTextDraw(g_font, "Press SPACE to screenshot",
        250.0f, 550.0f, 0xFFFFFFFF)

    // 检测空格键触发截图
    if (xgeKeyDown(XGE_KEY_SPACE))
        takeScreenshot();

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch92 - Screenshot Save PNG";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    xgeFontLoad(&g_font, "Roboto.ttf", 18.0f);

    xgeRun(onFrame, NULL);

    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • RenderTargetWindow:获取窗口默认渲染目标,用于回读当前帧像素。
  • ReadPixels:从 GPU 回读 RGBA 像素到 CPU 缓冲区,stride 为每行字节数。
  • ImageSavePNG:将 RGBA 像素编码为无损 PNG 文件,可在任何线程调用。
  • 按键触发:检测空格键按下时执行截图,文件名带序号避免覆盖。

要点与陷阱

  • iStride:每行字节数,通常为 width×4;允许大于 width×4(对齐填充)。
  • 像素格式:必须是 RGBA32(每通道 8 位)。
  • 线程:SavePNG 是 CPU 操作,可在任何线程调用。
  • 路径:目标目录必须存在,否则返回错误码。

进阶练习

  1. 实现 F12 截图功能:按键触发 → 回读 → 保存带时间戳文件名。
  2. 离屏渲染缩略图:RenderTarget 绘制场景 → 保存预览图。
图像保存效果
图:图像保存渲染效果