如何在 SDL 2 中获取并保存 BMP 屏幕截图?

Posted

技术标签:

【中文标题】如何在 SDL 2 中获取并保存 BMP 屏幕截图?【英文标题】:How do I take and save a BMP screenshot in SDL 2? 【发布时间】:2013-12-12 13:31:40 【问题描述】:

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

【问题讨论】:

【参考方案1】:

下面是一个将屏幕截图保存到 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;

干杯! -尼尔

【讨论】:

pixels = NULL; 应该是delete[] pixels;,否则数组会泄露。【参考方案2】:

如果您使用带有 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 page,其中包含设置窗口和 OpenGL 上下文的示例。

编辑:如果您想复制/粘贴此 sn-p,请记住添加一些错误检查

【讨论】:

感谢代码示例! invert the surface vertically 之后效果很好。 还要考虑到endianness :)【参考方案3】:
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;

【讨论】:

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

以上是关于如何在 SDL 2 中获取并保存 BMP 屏幕截图?的主要内容,如果未能解决你的问题,请参考以下文章

将特定窗口的屏幕截图保存为窗口中的 bmp

OpenGL 中的 BMP 屏幕截图

VB 如何获取屏幕图片数据保存在一个二进制数组里面?

delphi不用getdc如何屏幕截图

如何在 selenium 中截取屏幕截图并粘贴为 HTML 页面?

用 SDL2 平铺背景并显示前景