-
-
Save tobyhinloopen/c19f3553f81246b8ca48711415b499b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "image_data_png.h" | |
#include <png.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
void image_data_png_read(image_data_t *image_data, const char *filename) { | |
FILE *fp = fopen(filename, "rb"); | |
png_byte bit_depth; | |
png_byte color_type; | |
unsigned int y; | |
unsigned int x; | |
png_structp png_ptr = | |
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
if (!png_ptr) abort(); | |
png_infop info_ptr = png_create_info_struct(png_ptr); | |
if (!info_ptr) abort(); | |
if (setjmp(png_jmpbuf(png_ptr))) abort(); | |
png_init_io(png_ptr, fp); | |
png_read_info(png_ptr, info_ptr); | |
const unsigned int width = png_get_image_width(png_ptr, info_ptr); | |
const unsigned int height = png_get_image_height(png_ptr, info_ptr); | |
color_type = png_get_color_type(png_ptr, info_ptr); | |
bit_depth = png_get_bit_depth(png_ptr, info_ptr); | |
/* Read any color_type into 8bit depth, RGBA format. */ | |
/* See http://www.libpng.org/pub/png/libpng-manual.txt */ | |
if (bit_depth == 16) png_set_strip_16(png_ptr); | |
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); | |
/* PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. */ | |
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) | |
png_set_expand_gray_1_2_4_to_8(png_ptr); | |
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) | |
png_set_tRNS_to_alpha(png_ptr); | |
/* These color_type don't have an alpha channel then fill it with 0xff. */ | |
if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || | |
color_type == PNG_COLOR_TYPE_PALETTE) | |
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); | |
if (color_type == PNG_COLOR_TYPE_GRAY || | |
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
png_set_gray_to_rgb(png_ptr); | |
png_read_update_info(png_ptr, info_ptr); | |
png_bytep *row_pointers = | |
(png_bytep *)malloc(sizeof(row_pointers[0]) * height); | |
for (y = 0; y < height; y++) { | |
row_pointers[y] = (png_byte *)malloc(png_get_rowbytes(png_ptr, info_ptr)); | |
} | |
png_read_image(png_ptr, row_pointers); | |
fclose(fp); | |
image_data_resize(image_data, width, height); | |
for (y = 0; y < height; y++) { | |
for (x = 0; x < width; x++) { | |
png_byte *rgba = row_pointers[y] + x * 4; | |
image_data_put3(image_data, x, y, rgba[0], rgba[1], rgba[2]); | |
} | |
free(row_pointers[y]); | |
} | |
free(row_pointers); | |
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); | |
} | |
void image_data_png_write(image_data_t *image_data, const char *filename) { | |
// SOURCE: https://www.lemoda.net/c/write-png/ | |
FILE *fp; | |
png_structp png_ptr = NULL; | |
png_infop info_ptr = NULL; | |
size_t x, y; | |
png_byte **row_pointers = NULL; | |
/* The following number is set by trial and error only. I cannot | |
see where it it is documented in the libpng manual. | |
*/ | |
int pixel_size = 3; | |
int depth = 8; | |
fp = fopen(filename, "wb"); | |
if (!fp) abort(); | |
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
if (png_ptr == NULL) abort(); | |
info_ptr = png_create_info_struct(png_ptr); | |
if (info_ptr == NULL) abort(); | |
/* Set up error handling. */ | |
if (setjmp(png_jmpbuf(png_ptr))) abort(); | |
/* Set image attributes. */ | |
png_set_IHDR(png_ptr, info_ptr, image_data->width, image_data->height, depth, | |
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, | |
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | |
/* Initialize rows of PNG. */ | |
row_pointers = | |
png_malloc(png_ptr, image_data->height * sizeof(row_pointers[0])); | |
for (y = 0; y < image_data->height; y++) { | |
png_byte *row = | |
png_malloc(png_ptr, sizeof(uint8_t) * image_data->width * pixel_size); | |
row_pointers[y] = row; | |
for (x = 0; x < image_data->width; x++) { | |
rgb_t *pixel = image_data_at(image_data, x, y); | |
*row++ = pixel->r; | |
*row++ = pixel->g; | |
*row++ = pixel->b; | |
} | |
} | |
/* Write the image data to "fp". */ | |
png_init_io(png_ptr, fp); | |
png_set_rows(png_ptr, info_ptr, row_pointers); | |
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); | |
for (y = 0; y < image_data->height; y++) { | |
png_free(png_ptr, row_pointers[y]); | |
} | |
png_free(png_ptr, row_pointers); | |
png_destroy_write_struct(&png_ptr, &info_ptr); | |
} | |
void executable_bitmap_png_read(executable_bitmap_t *executable_bitmap, | |
const char *filename) { | |
image_data_png_read(&executable_bitmap->image_data, filename); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment