OpenGL snippets

From vegard.wiki
Revision as of 14:48, 25 February 2020 by Vegard (talk | contribs) (add link)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Saving the framebuffer to file

Python/PIL

from PIL import Image

pixels = glReadPixels(0, 0, window_width, window_height, GL_RGB, GL_UNSIGNED_BYTE)
image = Image.frombytes(mode="RGB", size=(window_width, window_height), data=pixels)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
image.save('output.png')

Note: This should work for any file type/extension that PIL supports.

May or may not work for widths which are not multiples of 4 or 8. YMMV.

C++/libpng

#include <libpng/png.h>

// http://www.labbookpages.co.uk/software/imgProc/libPNG.html
static void capture()
{
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);

        // round up width to a multiple of 8 avoid alignment problems
        unsigned int buffer_width = (width + 7) & ~7;
        unsigned int buffer_size = buffer_width * height * 3;
        auto buffer = std::make_unique<char []>(buffer_size);

        glReadnPixels(0, 0, buffer_width, height,
                GL_RGB, GL_UNSIGNED_BYTE, buffer_size, (void *) buffer.get());

        FILE *fp = fopen("output.png", "wb");
        if (!fp)
                error(EXIT_FAILURE, errno, "fopen()");

        auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
        if (!png_ptr)
                error(EXIT_FAILURE, 0, "png_create_write_struct()");

        auto info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
                error(EXIT_FAILURE, 0, "png_create_info_struct()");

        png_init_io(png_ptr, fp);
        png_set_IHDR(png_ptr, info_ptr, width, height,
                8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
                PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
        png_write_info(png_ptr, info_ptr);

        for (unsigned int y = 0; y < height; ++y)
                png_write_row(png_ptr, (png_bytep) &buffer[3 * buffer_width * (height - y - 1)]);

        png_write_end(png_ptr, info_ptr);
        fclose(fp);

        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
        png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
}

This uses GLFW to obtain the frambuffer size, but should be easy to adapt to other windowing APIs.

The error handling leaves something to be desired for now.

See also