将SDL纹理保存到文件

时间:2015-12-13 20:15:13

标签: sdl sdl-2

我正在尝试将纹理保存到png中,这是我唯一能得到的 是屏幕一部分的屏幕截图。

我的代码示例:

src_texture =  SDL_CreateTextureFromSurface( renderer, some_surface );
/*.........*/

/*create target texture */
SDL_Texture *tmp_texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_TARGET , w, h);
SDL_SetTextureBlendMode(tmp_texture, SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(renderer, tmp_texture);
SDL_RenderCopy(renderer, src_texture, NULL, NULL);

/*create surface and get pixels from texture*/
PixelFormat mask = GetMask(format);
s = SDL_CreateRGBSurface(0, w, h, 32, mask.Rmask, mask.Gmask, mask.Bmask, mask.Amask);
if (s) {
    SDL_SetRenderTarget(renderer, tmp_texture);
    SDL_RenderReadPixels(renderer, NULL, s->format->format, s->pixels, s->pitch);
    IMG_SavePNG(s, "image.png");

}
SDL_DestroyTexture(tmp_texture);

知道如何实现这个目标吗?

4 个答案:

答案 0 :(得分:3)

这是我的解决方法:

void save_texture(const char* file_name, SDL_Renderer* renderer, SDL_Texture* texture) {
    SDL_Texture* target = SDL_GetRenderTarget(renderer);
    SDL_SetRenderTarget(renderer, texture);
    int width, height;
    SDL_QueryTexture(texture, NULL, NULL, &width, &height);
    SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
    SDL_RenderReadPixels(renderer, NULL, surface->format->format, surface->pixels, surface->pitch);
    IMG_SavePNG(surface, file_name);
    SDL_FreeSurface(surface);
    SDL_SetRenderTarget(renderer, target);
}

此功能在文件写入之外没有任何副作用。这使插入变得容易,因为您不必担心渲染目标会被破坏。随意添加您认为合适的错误处理。

答案 1 :(得分:2)

我一直在寻找相同的东西,当我找不到一个执行此操作的片段时,我感到很失望"简单"任务。

所以,我继续为下一个想要它的人做了一个。我不会在生产代码中使用它,它只是用于调试。在SDL 2.0.7中测试。

它做什么

将所有SDL_Texture保存到.bmp文件。

从技术上讲,它会将SDL_Texture转换为SDL_Surface,并将其保存为.bmp

示例用例

特别适合:

  • 检查在运行时生成的大型纹理图集
  • 一次性探索大量生成的水平
  • 保存屏幕截图
  • 在您喜欢的图像编辑器中查看任何生成或复合纹理

用法

非常简单,只需将SDL_Renderer与您要保存的SDL_Texture一起传递,并filename保存到。

此外,这将破坏任何文件,所以要小心。

代码将所有内容强制为RGBA32格式,尽管它很简单,可以调整为您想要的任何格式。如果您愿意,可以通过将其作为参数传递给format来加载SDL_QueryTexture,以自动检测输入纹理的格式并将其用于输出文件。

限制

如果您想要增强此代码,请考虑以下几点。

  • 内存使用:这需要大约纹理内存的4倍,如果您尝试保存已经是可渲染目标的纹理,则需要3倍。这可能是太多的记忆,取决于你的纹理有多大。
  • 文件压缩:图像数据以原始格式存储,因此没有压缩。这可能会产生过大的文件。如果您想将此用于屏幕截图,您可能希望将此原始格式用作pngjpg或其他压缩格式的垫脚石。
  • 错误处理:错误处理方式不多。你可能想要更强大的东西。

/* Usage example */
save_texture(sdlttyDisplay->ren, sdlttyDisplay->font_tex, "image.bmp");
void save_texture(SDL_Renderer *ren, SDL_Texture *tex, const char *filename)
{
    SDL_Texture *ren_tex;
    SDL_Surface *surf;
    int st;
    int w;
    int h;
    int format;
    void *pixels;

    pixels  = NULL;
    surf    = NULL;
    ren_tex = NULL;
    format  = SDL_PIXELFORMAT_RGBA32;

    /* Get information about texture we want to save */
    st = SDL_QueryTexture(tex, NULL, NULL, &w, &h);
    if (st != 0) {
        SDL_Log("Failed querying texture: %s\n", SDL_GetError());
        goto cleanup;
    }

    ren_tex = SDL_CreateTexture(ren, format, SDL_TEXTUREACCESS_TARGET, w, h);
    if (!ren_tex) {
        SDL_Log("Failed creating render texture: %s\n", SDL_GetError());
        goto cleanup;
    }

    /*
     * Initialize our canvas, then copy texture to a target whose pixel data we 
     * can access
     */
    st = SDL_SetRenderTarget(ren, ren_tex);
    if (st != 0) {
        SDL_Log("Failed setting render target: %s\n", SDL_GetError());
        goto cleanup;
    }

    SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0x00);
    SDL_RenderClear(ren);

    st = SDL_RenderCopy(ren, tex, NULL, NULL);
    if (st != 0) {
        SDL_Log("Failed copying texture data: %s\n", SDL_GetError());
        goto cleanup;
    }

    /* Create buffer to hold texture data and load it */
    pixels = malloc(w * h * SDL_BYTESPERPIXEL(format));
    if (!pixels) {
        SDL_Log("Failed allocating memory\n");
        goto cleanup;
    }

    st = SDL_RenderReadPixels(ren, NULL, format, pixels, w * SDL_BYTESPERPIXEL(format));
    if (st != 0) {
        SDL_Log("Failed reading pixel data: %s\n", SDL_GetError());
        goto cleanup;
    }

    /* Copy pixel data over to surface */
    surf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, SDL_BITSPERPIXEL(format), w * SDL_BYTESPERPIXEL(format), format);
    if (!surf) {
        SDL_Log("Failed creating new surface: %s\n", SDL_GetError());
        goto cleanup;
    }

    /* Save result to an image */
    st = SDL_SaveBMP(surf, filename);
    if (st != 0) {
        SDL_Log("Failed saving image: %s\n", SDL_GetError());
        goto cleanup;
    }

    SDL_Log("Saved texture as BMP to \"%s\"\n", filename);

cleanup:
    SDL_FreeSurface(surf);
    free(pixels);
    SDL_DestroyTexture(ren_tex);
}

答案 2 :(得分:0)

为了将部分屏幕保存到文件中,最好创建RGBSurface:

SDL_Surface *ss = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);

Here is SDL_CreateRGBSurface documentation

下一步与您的代码相同 - 使用正确颜色格式的SDL_RenderReadPixels。 获得此功能后,您只需使用SDL_SaveBMP或其他功能进行保存即可。

答案 3 :(得分:0)

你设法解决了这个问题吗?使用您的代码,我的程序在SDL_RenderReadPixels()调用时崩溃。

如果将纹理更改为SDL_TEXTUREACCESS_STREAMING,则可以使用上述方法正确捕获它,但请注意仅在实际渲染器的分辨率中。如果纹理较大,它将被切断。