Function to save 24bit RGB data as PNG

This commit is contained in:
Kovid Goyal
2025-11-16 23:28:11 +05:30
parent 9bcbdb9f14
commit bfca1763f2
3 changed files with 19 additions and 7 deletions

View File

@@ -215,7 +215,7 @@ save_texture_as_png(uint32_t texture_id, const char *filename) {
data[i] = (r << 0) | (g << 8) | (b << 16) | (a << 24);
}
const char *png = png_from_32bit_rgba(data, width, height, &sz, true);
const char *png = png_from_32bit_rgba((char*)data, width, height, &sz, true);
if (!sz) fatal("Failed to save PNG to %s with error: %s", filename, png);
free(data);
FILE* file = fopen(filename, "wb");

View File

@@ -163,8 +163,8 @@ png_write_to_memory(png_structp png_ptr, png_bytep data, png_size_t length) {
}
static void png_flush_memory(png_structp png_ptr) { (void)png_ptr; }
const char*
png_from_32bit_rgba(uint32_t *data, size_t width, size_t height, size_t *out_size, bool flip_vertically) {
static const char*
create_png_from_data(char *data, size_t width, size_t height, size_t stride, size_t *out_size, bool flip_vertically, int color_type) {
*out_size = 0;
png_memory_write_state state = {.capacity=width*height * sizeof(uint32_t)};
state.buffer = malloc(state.capacity);
@@ -181,7 +181,7 @@ png_from_32bit_rgba(uint32_t *data, size_t width, size_t height, size_t *out_siz
return("Error during PNG creation\n");
}
png_set_write_fn(png_ptr, &state, png_write_to_memory, png_flush_memory);
png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA,
png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// Allocate memory for row pointers
png_bytep *row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
@@ -190,8 +190,8 @@ png_from_32bit_rgba(uint32_t *data, size_t width, size_t height, size_t *out_siz
free(state.buffer);
return ("Failed to allocate memory for row pointers");
}
if (flip_vertically) for (size_t y = 0; y < height; y++) row_pointers[height - 1 - y] = (png_byte*)&data[y * width];
else for (size_t y = 0; y < height; y++) row_pointers[y] = (png_byte*)&data[y * width];
if (flip_vertically) for (size_t y = 0; y < height; y++) row_pointers[height - 1 - y] = (png_byte*)&data[y * stride];
else for (size_t y = 0; y < height; y++) row_pointers[y] = (png_byte*)&data[y * stride];
png_write_info(png_ptr, info_ptr);
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, NULL);
@@ -201,6 +201,17 @@ png_from_32bit_rgba(uint32_t *data, size_t width, size_t height, size_t *out_siz
return (char*)state.buffer;
}
const char*
png_from_32bit_rgba(char *data, size_t width, size_t height, size_t *out_size, bool flip_vertically) {
return create_png_from_data(data, width, height, 4 * width, out_size, flip_vertically, PNG_COLOR_TYPE_RGBA);
}
const char*
png_from_24bit_rgb(char *data, size_t width, size_t height, size_t *out_size, bool flip_vertically) {
return create_png_from_data(data, width, height, 3 * width, out_size, flip_vertically, PNG_COLOR_TYPE_RGB);
}
static void
png_error_handler(png_read_data *d UNUSED, const char *code, const char *msg) {
if (!PyErr_Occurred()) PyErr_Format(PyExc_ValueError, "[%s] %s", code, msg);

View File

@@ -28,4 +28,5 @@ typedef struct png_read_data {
} png_read_data;
void inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz, int max_image_dimension);
const char* png_from_32bit_rgba(uint32_t *data, size_t width, size_t height, size_t *out_size, bool flip_vertically);
const char* png_from_32bit_rgba(char *data, size_t width, size_t height, size_t *out_size, bool flip_vertically);
const char* png_from_24bit_rgb(char *data, size_t width, size_t height, size_t *out_size, bool flip_vertically);