Skip to content

Instantly share code, notes, and snippets.

@JakubVanek
Last active May 5, 2023 21:10
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JakubVanek/4ec92317274c12d2dec9 to your computer and use it in GitHub Desktop.
Save JakubVanek/4ec92317274c12d2dec9 to your computer and use it in GitHub Desktop.
Convert raw BGRA framebuffer to RGB png file
This program can be used to convert raw BGRA 8888 framebuffer to standard PNG file.
#include <png.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
typedef struct {
uint8_t red;
uint8_t green;
uint8_t blue;
} pixel_t;
typedef struct {
pixel_t *pixels;
size_t width;
size_t height;
} bitmap_t;
static pixel_t * pixel_at (bitmap_t *bitmap, int x, int y) {
return bitmap->pixels + x + bitmap->width * y;
}
static int save_png_to_file (bitmap_t *bitmap, const char* path) {
FILE *p_file;
png_structp p_png = NULL;
png_infop p_info = NULL;
size_t x, y;
png_byte ** row_pointers = NULL;
int status = -1;
int pixel_size = 3;
int depth = 8;
p_file = fopen(path, "wb");
if (!p_file) {
goto fopen_failed;
}
p_png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (p_png == NULL) {
goto png_create_write_struct_failed;
}
p_info = png_create_info_struct (p_png);
if (p_info == NULL) {
goto png_create_info_struct_failed;
}
if (setjmp (png_jmpbuf (p_png))) {
goto png_failure;
}
png_set_IHDR ( p_png,
p_info,
bitmap->width,
bitmap->height,
depth,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
row_pointers = png_malloc (p_png, bitmap->height * sizeof (png_byte*));
for (y = 0; y < bitmap->height; ++y) {
png_byte *row = png_malloc (p_png, sizeof (uint8_t) * bitmap->width * pixel_size);
row_pointers[y] = row;
for (x = 0; x < bitmap->width; ++x) {
pixel_t *pixel = pixel_at (bitmap, x, y);
*row++ = pixel->red;
*row++ = pixel->green;
*row++ = pixel->blue;
}
}
png_init_io (p_png, p_file);
png_set_rows (p_png, p_info, row_pointers);
png_write_png (p_png, p_info, PNG_TRANSFORM_IDENTITY, NULL);
status = 0;
for (y = 0; y < bitmap->height; y++) {
png_free (p_png, row_pointers[y]);
}
png_free (p_png, row_pointers);
png_failure:
png_create_info_struct_failed:
png_destroy_write_struct(&p_png, &p_info);
png_create_write_struct_failed:
fclose(p_file);
fopen_failed:
return status;
}
int main (int argc, char **argv) {
size_t width, height, read = 0, length;
int i, status = 0;
char *input, *output;
uint8_t *buffer = NULL;
bitmap_t *bitmap = NULL;
pixel_t *pixel_out;
uint8_t *pixel_in;
FILE * fp = NULL;
if (argc != 5) {
printf("Usage: %s <width> <height> <input> <output>\n", argv[0]);
exit(1);
}
width = (size_t) atoi (argv[1]);
height = (size_t) atoi (argv[2]);
input = argv[3];
output = argv[4];
length = width * height * 4;
buffer = malloc (length);
bitmap = malloc (sizeof (pixel_t*) + sizeof (size_t) * 2);
bitmap->pixels = malloc(sizeof (pixel_t) * width * height);
bitmap->width = width;
bitmap->height = height;
fp = fopen(input, "rb");
if (!fp) {
printf ("Error opening file (%d): %s.\n", errno, strerror (errno));
status = 1;
goto free_val;
}
do {
read = fread (buffer + read, length - read, 1, fp);
} while (read > 0);
read = fclose (fp);
if (read == EOF) {
printf ("Error closing file (%d): %s.\n", errno, strerror (errno));
status = 1;
goto free_val;
}
pixel_in = buffer;
pixel_out = bitmap->pixels;
for (i = 0; i < width * height; i++) {
pixel_out->blue = *(pixel_in++);
pixel_out->green = *(pixel_in++);
pixel_out->red = *(pixel_in++);
pixel_in++; // ignore alpha
pixel_out++; // to next pixel
}
pixel_in = NULL;
pixel_out = NULL;
int retval = save_png_to_file (bitmap, output);
if (retval != 0) {
printf ("Error saving PNG.\n");
goto free_val;
}
free_val:
free(buffer);
free(bitmap->pixels);
free(bitmap);
return status;
}
@JakubVanek
Copy link
Author

Yes, there's unnecessary copying to bitmap_t, but I've created this mainly for fun. PNG write function comes from www.lemoda.net/c/write-png/.

@JakubVanek
Copy link
Author

For this program to work correctly fbset must return rgba 8/16,8/8,8/0,0/0 and bit depth must be 32.

@JakubVanek
Copy link
Author

How to compile: enter this to terminal while you're in the directory with data.c

gcc data.c -O2 -lpng -o data

Usage:

  • use framebuffer:
    ./data <fb width> <fb height> /dev/fb0 <out>.png (replace <...> with corresponding values)
  • use framebuffer snapshot:
dd if=/dev/fb0 of=fb.raw
./data <fb width> <fb height> fb.raw <out>.png

Replace <...> with corresponding values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment