Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I take and save a BMP screenshot in SDL 2?

Using just a given SDL_Window* and SDL_Renderer*, how can I create and save a screenshot in SDL 2.0?

like image 487
Neil Flodin Avatar asked Nov 27 '13 03:11

Neil Flodin


3 Answers

If you are using OpenGL with SDL2 you can call glReadPixels directly instead of using the info surface and renderer. Here is an example (without error checking).

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;
}

Here's the SDL wiki page with an example of setting up the window and an OpenGL context.

Edit: If you are tempted to copy/paste this snippet, remember to add some error checking

like image 36
szmoore Avatar answered Nov 15 '22 23:11

szmoore


Below is a function for saving a screenshot in SDL 2 taken from a library I'm currently writing.

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

like image 86
Neil Flodin Avatar answered Nov 16 '22 00:11

Neil Flodin


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;
}
like image 21
Severin Turin Avatar answered Nov 16 '22 01:11

Severin Turin