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

3

16

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

Abstention answered 27/11, 2013 at 3:43 Comment(0)
A
11

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

Abstention answered 27/11, 2013 at 3:43 Comment(1)
pixels = NULL; should be delete[] pixels;, otherwise the array is leaked.Prepossessing
S
9

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

Supremacy answered 15/4, 2014 at 18:13 Comment(2)
Thanks for the code sample! It works pretty good after you invert the surface vertically.Humiliating
And also take into account the endianness :)Humiliating
B
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;
}
Balaam answered 3/3, 2021 at 11:44 Comment(1)
Please read the guidelines about how to ask a question: stackoverflow.com/help/how-to-ask. Specifically, describe your problem, your attempt, and the difficulties with it.Burnaby

© 2022 - 2025 — McMap. All rights reserved.