OpenGL snippets: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
(add link) |
|||
(3 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
== Saving the framebuffer to file == |
== Saving the framebuffer to file == |
||
=== Python === |
=== Python/PIL === |
||
<source lang="Python"> |
<source lang="Python"> |
||
Line 15: | Line 15: | ||
Note: This should work for any file type/extension that PIL supports. |
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 === |
|||
<source lang="C++"> |
|||
#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); |
|||
} |
|||
</source> |
|||
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 == |
|||
* [[GLSL snippets]] |
|||
[[Category:Graphics programming]] |
[[Category:Graphics programming]] |
Latest revision as of 14:48, 25 February 2020
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.