diff --git a/Makefile b/Makefile index ed299bb..e758797 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,9 @@ all: $(APPS) gbdb: apps/gbdb gbasm: apps/gbasm threading: apps/threading +bmp: apps/bmp_test -.PHONY: gbasm-test tests threading +.PHONY: gbasm-test tests threading bmp TESTS = $(patsubst %.o, %, $(filter %/test.o, $(ALL_OBJS))) tests: $(TESTS) diff --git a/src/apps/bmp_test.c b/src/apps/bmp_test.c new file mode 100644 index 0000000..67ef6e0 --- /dev/null +++ b/src/apps/bmp_test.c @@ -0,0 +1,22 @@ +#include "common/bmp.h" + + +int main(int argc, const char **argv) +{ + struct bmp *bmp; + uint32_t width = 144; + uint32_t height = 160; + char *buffer; + int x, y; + + bmp = bmp_new(BMP_GRAYSCALE, width, height); + buffer = bmp_get_pixel_buffer(bmp); + + for (x = 0; x < width; x++) { + for (y = 0; y < height; y++) { + buffer[x + (y * width)] = (y + x) / 2; + } + } + + bmp_write_file(bmp, "test.bmp"); +} diff --git a/src/common/bmp.c b/src/common/bmp.c new file mode 100644 index 0000000..84b5bd0 --- /dev/null +++ b/src/common/bmp.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include + +#include "common/bmp.h" + +// All values are little endian + +struct bmp_file_header { + char type[2]; + uint32_t size; /* File size */ + uint16_t reserved1; + uint16_t reserved2; + uint32_t image_offset; +} __attribute__((packed)); + +struct bmp_image_header { + uint32_t size; /* Header size */ + uint32_t width; + uint32_t height; + uint16_t planes; + uint16_t bits_per_pixel; + uint32_t compression; + uint32_t image_size; + int32_t x_res; + int32_t y_res; + uint32_t num_colors; + uint32_t important_colors; +} __attribute__((packed)); + +struct bmp { + struct bmp_file_header file_header; + struct bmp_image_header image_header; + + uint32_t *color_data; + size_t color_data_size; + + char *pixel_data; + size_t pixel_data_size; +}; + +#define BMP_GRAYSCALE_BITS_PER_PIXEL 8 + +struct bmp *bmp_new(enum bmp_type type, uint32_t pixels_width, + uint32_t pixels_height) +{ + struct bmp *bmp; + uint32_t bits_per_pixel; + uint32_t num_colors; + int i; + + if (type != BMP_GRAYSCALE) { + return NULL; + } + + bmp = malloc(sizeof *bmp); + if (bmp == NULL) { + return NULL; + } + + bits_per_pixel = BMP_GRAYSCALE_BITS_PER_PIXEL; + num_colors = 256; + + bmp->file_header.type[0] = 'B'; + bmp->file_header.type[1] = 'M'; + bmp->file_header.size = sizeof(bmp->file_header) + + sizeof(bmp->image_header) + + (pixels_width * pixels_height * bits_per_pixel); + bmp->file_header.reserved1 = 0; + bmp->file_header.reserved2 = 0; + bmp->file_header.image_offset = sizeof(bmp->file_header) + + sizeof(bmp->image_header) + + num_colors * sizeof(uint32_t); + + bmp->image_header.size = sizeof(bmp->image_header); + bmp->image_header.width = pixels_width; + bmp->image_header.height = pixels_height; + bmp->image_header.planes = 1; + bmp->image_header.bits_per_pixel = bits_per_pixel; + bmp->image_header.compression = 0; + bmp->image_header.image_size = 0; + bmp->image_header.x_res = 0; + bmp->image_header.y_res = 0; + bmp->image_header.num_colors = num_colors; + bmp->image_header.important_colors = num_colors; + + bmp->color_data_size = (1U << bits_per_pixel) * sizeof(uint32_t); + bmp->color_data = malloc(bmp->color_data_size); + + /* Initialize the color pallete with equally-spaced shades of gray */ + for (i = 0; i < 1U << bits_per_pixel; i++) { + bmp->color_data[i] = (i << 16) | (i << 8) | i; + } + + bmp->pixel_data_size = pixels_width * pixels_height * bits_per_pixel; + bmp->pixel_data = malloc(bmp->pixel_data_size); + + return bmp; +} + +char *bmp_get_pixel_buffer(struct bmp *bmp) +{ + return bmp->pixel_data; +} + +int bmp_write_file(struct bmp *bmp, const char *filename) +{ + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR); + if (fd < 0) { + return fd; + } + + // TODO: Check these return codes + write(fd, &bmp->file_header, sizeof(bmp->file_header)); + write(fd, &bmp->image_header, sizeof(bmp->image_header)); + write(fd, bmp->color_data, bmp->color_data_size); + write(fd, bmp->pixel_data, bmp->pixel_data_size); + close(fd); + + return 0; +} diff --git a/src/common/bmp.h b/src/common/bmp.h new file mode 100644 index 0000000..1276075 --- /dev/null +++ b/src/common/bmp.h @@ -0,0 +1,14 @@ +#include + +enum bmp_type { + BMP_GRAYSCALE +}; + +struct bmp; + +struct bmp *bmp_new(enum bmp_type type, uint32_t pixels_width, + uint32_t pixels_height); + +char *bmp_get_pixel_buffer(struct bmp *bmp); + +int bmp_write_file(struct bmp *bmp, const char *filename);