如何在SDL 2中进行BMP截图并保存?

16

如何仅使用给定的SDL_Window*和SDL_Renderer*创建并保存SDL 2.0中的屏幕截图?

3个回答

11
以下是我目前正在编写的库中使用的保存SDL 2屏幕截图的函数。
bool saveScreenshotBMP(std::string filepath, SDL_Window* SDLWindow, SDL_Renderer* SDLRenderer) {
    SDL_Surface* saveSurface = NULL;
    SDL_Surface* infoSurface = NULL;
    infoSurface = SDL_GetWindowSurface(SDLWindow);
    if (infoSurface == NULL) {
        std::cerr << "Failed to create info surface from window in saveScreenshotBMP(string), SDL_GetError() - " << SDL_GetError() << "\n";
    } else {
        unsigned char * pixels = new (std::nothrow) unsigned char[infoSurface->w * infoSurface->h * infoSurface->format->BytesPerPixel];
        if (pixels == 0) {
            std::cerr << "Unable to allocate memory for screenshot pixel data buffer!\n";
            return false;
        } else {
            if (SDL_RenderReadPixels(SDLRenderer, &infoSurface->clip_rect, infoSurface->format->format, pixels, infoSurface->w * infoSurface->format->BytesPerPixel) != 0) {
                std::cerr << "Failed to read pixel data from SDL_Renderer object. SDL_GetError() - " << SDL_GetError() << "\n";
                delete[] pixels;
                return false;
            } else {
                saveSurface = SDL_CreateRGBSurfaceFrom(pixels, infoSurface->w, infoSurface->h, infoSurface->format->BitsPerPixel, infoSurface->w * infoSurface->format->BytesPerPixel, infoSurface->format->Rmask, infoSurface->format->Gmask, infoSurface->format->Bmask, infoSurface->format->Amask);
                if (saveSurface == NULL) {
                    std::cerr << "Couldn't create SDL_Surface from renderer pixel data. SDL_GetError() - " << SDL_GetError() << "\n";
                    delete[] pixels;
                    return false;
                }
                SDL_SaveBMP(saveSurface, filepath.c_str());
                SDL_FreeSurface(saveSurface);
                saveSurface = NULL;
            }
            delete[] pixels;
        }
        SDL_FreeSurface(infoSurface);
        infoSurface = NULL;
    }
    return true;
}

Cheers! -Neil


3
pixels = NULL; 应该改为 delete[] pixels;,否则数组会被泄漏(leak)。 - emlai

9
如果您正在使用SDL2和OpenGL,可以直接调用glReadPixels而不是使用信息表面和渲染器。这里是一个例子(没有错误检查)。
void Screenshot(int x, int y, int w, int h, const char * filename)
{
    unsigned char * pixels = new unsigned char[w*h*4]; // 4 bytes for RGBA
    glReadPixels(x,y,w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

    SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(pixels, w, h, 8*4, w*4, 0,0,0,0);
    SDL_SaveBMP(surf, filename);

    SDL_FreeSurface(surf);
    delete [] pixels;
}

这里是 SDL wiki页面,其中包含设置窗口和OpenGL上下文的示例。
编辑:如果你想复制/粘贴此片段,请记得添加一些错误检查

1
感谢提供代码示例!在您垂直翻转表面之后,它的效果非常好。 - AntonK
1
还要考虑字节序问题(请参考:https://stackoverflow.com/a/38038504/536172) :) - AntonK

1
void Screenshot(int x, int y, int w, int h, const char * filename)
{
Uint32 rmask, gmask, bmask, amask;

rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;

unsigned char * pixels = new unsigned char[w*h*4]; // 4 bytes for RGBA
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

SDL_Surface * surf = SDL_CreateRGBSurfaceFrom(pixels, w, h, 8*4, w*4, rmask, gmask, bmask, amask);
SDL_SaveBMP(surf, filename);

SDL_FreeSurface(surf);
delete [] pixels;
}

请阅读有关如何提问的指南:https://stackoverflow.com/help/how-to-ask。具体来说,请描述您的问题、您的尝试以及遇到的困难。 - Seriously

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接