From 5e8bab38f0b0fb8c2d0c1be8a9c7fd287d2ca036 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Fri, 13 Mar 2020 22:35:41 +0100 Subject: [PATCH] cleaned code, transparency now actually working --- .gitignore | 4 +- images/bmp-format.c | 91 +++++++++++++++++++++ images/images.c | 190 +++++++++++++++++++------------------------- images/images.h | 35 +++++--- main.c | 73 ++++++++++++----- 5 files changed, 251 insertions(+), 142 deletions(-) create mode 100644 images/bmp-format.c diff --git a/.gitignore b/.gitignore index 386f581..82f4fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.out -*.o \ No newline at end of file +*.o + +*.bmp \ No newline at end of file diff --git a/images/bmp-format.c b/images/bmp-format.c new file mode 100644 index 0000000..4837218 --- /dev/null +++ b/images/bmp-format.c @@ -0,0 +1,91 @@ +#include +#include +#include "images.h" + +// write an int to a byte array +void bmp__write_int(char* bytes, int num) { + for (int i = 0; i < 4; i++) { + bytes[i] = num >> (i * 8); + } +} + +void bmp__write_byte(char* bytes, int num) { + bytes[0] = (char) num; +} + +void bmp__write_16bit(char* bytes, int num) { + for (int i = 0; i < 2; i++) { + bytes[i] = num >> (i * 8); + } +} + +int bmp__align_to_four_bytes(int size) { + int os = size % 4; + return os == 0 ? size : size + (4 - os); +} + +int bmp__image_byte_size(Image image) { + // calculate size: + // bitmap file header = 14 + // BITMAPCOREHEADER = 12 bytes + int size = 14 + 12; + // width must be padded to align to 4 bytes + int width_bytes = bmp__align_to_four_bytes(image.width * 3); // 3 bytes per pixel + // add width_bytes * height to total size + size += width_bytes * image.height; + + return size; +} + +// header format: +// BMP header (14 bytes) +// 0x42 0x4D "BM" +// 0xAA 0xBB 0xCC 0xDD bmp file size (int) +// 0x00 0x00 0x00 0x00 nulls +// 0x1A 0x00 0x00 0x00 pixel array offset (int) (= 14 + 12); +// DIB Header (BITMAPCOREHEADER) (12 bytes) +// 0x0C 0x00 0x00 0x00 header size (int) (= 12) +// 0xAA 0xBB width (unsigned 16 bit int) +// 0xCC 0xDD height (unsigned 16 bit int) +// 0x01 0x00 number of color planes (must be 1) +// 0x18 0x00 number of bits per pixel (3 * 8 = 24) + +int image_save_bmp(Image image, char* path) { + int size = bmp__image_byte_size(image); + char* bytes = calloc(sizeof(char), size); + // magic bytes, signature "BM" + bytes[0] = 0x42; + bytes[1] = 0x4d; + // write size to header + bmp__write_int(bytes + 2, size); + // the next 4 byte are zeros + // piyel array offset + bmp__write_int(bytes + 10, 14 + 12); + bmp__write_int(bytes + 14, 12); + bmp__write_16bit(bytes + 18, image.width); // width + bmp__write_16bit(bytes + 20, image.height); // height + bmp__write_16bit(bytes + 22, 1); // color planes + bmp__write_16bit(bytes + 24, 3 * 8); // bits per pixel + + int byte_offset = 26; + int byte_pos = 0; + int line; + for (line = 0; line < image.height; line++) { + byte_pos = 0; + for (int px = 0; px < image.width * 3; px += 3) { + bytes[byte_offset + byte_pos++] = image.bitmap[line][px + 2]; + bytes[byte_offset + byte_pos++] = image.bitmap[line][px + 1]; + bytes[byte_offset + byte_pos++] = image.bitmap[line][px + 0]; + } + byte_offset += bmp__align_to_four_bytes(byte_pos); + } + + printf("generated %i bytes out of %i calculated ones\n", byte_offset, size); + + FILE *fp = fopen(path, "w"); + int written = fwrite(bytes, sizeof(char), size, fp); + printf("wrote %i bytes...\n", written); + fclose(fp); + free(bytes); + return 1; +} diff --git a/images/images.c b/images/images.c index 7bccef1..410577c 100644 --- a/images/images.c +++ b/images/images.c @@ -2,30 +2,9 @@ #include #include "images.h" -// write an int to a byte array -void write_int(char* bytes, int num) { - for (int i = 0; i < 4; i++) { - bytes[i] = num >> (i * 8); - } -} - -void write_byte(char* bytes, int num) { - bytes[0] = (char) num; -} - -void write_16bit(char* bytes, int num) { - for (int i = 0; i < 2; i++) { - bytes[i] = num >> (i * 8); - } -} - -int align_to_four_bytes(int size) { - int os = size % 4; - return os == 0 ? size : size + (4 - os); -} int image_new(int width, int height, Image* img) { - //Image* img = malloc(sizeof(Image)); + //Image img = malloc(sizeof(Image)); if (img == NULL) return 0; @@ -42,101 +21,46 @@ int image_new(int width, int height, Image* img) { return 1; } -int image_byte_size(Image *image) { - // calculate size: - // bitmap file header = 14 - // BITMAPCOREHEADER = 12 bytes - int size = 14 + 12; - // width must be padded to align to 4 bytes - int width_bytes = align_to_four_bytes(image->width * 3); // 3 bytes per pixel - // add width_bytes * height to total size - size += width_bytes * image->height; - - return size; -} - -// header format: -// BMP header (14 bytes) -// 0x42 0x4D "BM" -// 0xAA 0xBB 0xCC 0xDD bmp file size (int) -// 0x00 0x00 0x00 0x00 nulls -// 0x1A 0x00 0x00 0x00 pixel array offset (int) (= 14 + 12); -// DIB Header (BITMAPCOREHEADER) (12 bytes) -// 0x0C 0x00 0x00 0x00 header size (int) (= 12) -// 0xAA 0xBB width (unsigned 16 bit int) -// 0xCC 0xDD height (unsigned 16 bit int) -// 0x01 0x00 number of color planes (must be 1) -// 0x18 0x00 number of bits per pixel (3 * 8 = 24) - -int image_save(Image* image, char* path) { - int size = image_byte_size(image); - char* bytes = calloc(sizeof(char), size); - // magic bytes, signature "BM" - bytes[0] = 0x42; - bytes[1] = 0x4d; - // write size to header - write_int(bytes + 2, size); - // the next 4 byte are zeros - // piyel array offset - write_int(bytes + 10, 14 + 12); - write_int(bytes + 14, 12); - write_16bit(bytes + 18, image->width); // width - write_16bit(bytes + 20, image->height); // height - write_16bit(bytes + 22, 1); // color planes - write_16bit(bytes + 24, 3 * 8); // bits per pixel - - int byte_offset = 26; - int byte_pos = 0; - int line; - for (line = 0; line < image->height; line++) { - byte_pos = 0; - for (int px = 0; px < image->width * 3; px += 3) { - bytes[byte_offset + byte_pos++] = image->bitmap[line][px + 2]; - bytes[byte_offset + byte_pos++] = image->bitmap[line][px + 1]; - bytes[byte_offset + byte_pos++] = image->bitmap[line][px + 0]; - } - byte_offset += align_to_four_bytes(byte_pos); - } +int image_set_px(Image image, int x, int y, int r, int g, int b) { + if (!image_check_coords(image, x, y)) return 0; - printf("generated %i bytes out of %i calculated ones\n", byte_offset, size); + image.bitmap[y][(3 * x) + 0] = (char) r; + image.bitmap[y][(3 * x) + 1] = (char) g; + image.bitmap[y][(3 * x) + 2] = (char) b; - FILE *fp = fopen(path, "w"); - int written = fwrite(bytes, sizeof(char), size, fp); - printf("wrote %i bytes...\n", written); - fclose(fp); - free(bytes); return 1; } - -int image_set_px(Image* image, int x, int y, int r, int g, int b) { +int image_set_px_c(Image image, int x, int y, Color color) { if (!image_check_coords(image, x, y)) return 0; - image->bitmap[y][(3 * x) + 0] = (char) r; - image->bitmap[y][(3 * x) + 1] = (char) g; - image->bitmap[y][(3 * x) + 2] = (char) b; + if (color.alpha == 0) return 1; - return 1; -} -int image_set_px_c(Image* image, int x, int y, Color* color) { - if (!image_check_coords(image, x, y)) return 0; + if (color.alpha == 1) { + image.bitmap[y][(3 * x) + 0] = color.r; + image.bitmap[y][(3 * x) + 1] = color.g; + image.bitmap[y][(3 * x) + 2] = color.b; + } else { + + //printf("adding %d to %f\n", (color.alpha * color.r), ((1.0f - color.alpha) * (image.bitmap[y][(3 * x) + 0]/* & 0x000000ff */))); - image->bitmap[y][(3 * x) + 0] = (char) color->r; - image->bitmap[y][(3 * x) + 1] = (char) color->g; - image->bitmap[y][(3 * x) + 2] = (char) color->b; + image.bitmap[y][(3 * x) + 0] = (color.alpha * (color.r/* & 0x000000ff */)) + ((1.0f - color.alpha) * (image.bitmap[y][(3 * x) + 0]/* & 0x000000ff */)); + image.bitmap[y][(3 * x) + 1] = (color.alpha * (color.g/* & 0x000000ff */)) + ((1.0f - color.alpha) * (image.bitmap[y][(3 * x) + 1]/* & 0x000000ff */)); + image.bitmap[y][(3 * x) + 2] = (color.alpha * (color.b/* & 0x000000ff */)) + ((1.0f - color.alpha) * (image.bitmap[y][(3 * x) + 2]/* & 0x000000ff */)); + } return 1; } -int image_check_coords(Image* image, int x, int y) { - return x >= 0 && x < image->width && - y >= 0 && y < image->height; +int image_check_coords(Image image, int x, int y) { + return x >= 0 && x < image.width && + y >= 0 && y < image.height; } -int image_destroy(Image* image) { - for (int i = 0; i < image->height; i++) { - free(image->bitmap[i]); +int image_destroy(Image image) { + for (int i = 0; i < image.height; i++) { + free(image.bitmap[i]); } - free(image->bitmap); + free(image.bitmap); return 1; } @@ -144,15 +68,43 @@ int image_destroy(Image* image) { ///////// Colors -Color* color_new(int r, int g, int b) { - Color* c = malloc(sizeof(Color)); - c->r = r; - c->g = g; - c->b = b; +Color color_new(int r, int g, int b) { + Color c; + c.r = r; + c.g = g; + c.b = b; + c.alpha = 1; + return c; +} + +Color color_new_alpha(int r, int g, int b, float alpha) { + Color c; + c.r = r; + c.g = g; + c.b = b; + c.alpha = alpha; return c; } -int image_draw_rect(Image* image, int x1, int y1, int x2, int y2, Color* color) { +void print_color(Color c) { + printf("color is: #%02hhX%02hhX%02hhX\n", c.r, c.g, c.b); +} + +Color color_mix(Color c1, Color c2, float ratio) { + return color_new_alpha( + ratio * c1.r + ((1 - ratio) * c2.r), + ratio * c1.g + ((1 - ratio) * c2.g), + ratio * c1.b + ((1 - ratio) * c2.b), + ratio * c1.alpha + ((1 - ratio) * c2.alpha) + ); +} + + + + +//// IMAGE DRAWING HELPERS + +int image_draw_rect(Image image, int x1, int y1, int x2, int y2, Color color) { int retval = 1; int y; for (; x1 < x2; x1++) { @@ -164,3 +116,25 @@ int image_draw_rect(Image* image, int x1, int y1, int x2, int y2, Color* color) return retval; } +int image_draw_circ(Image image, int x, int y, int r, Color color) { + int retval = 1; + int i, j, r2 = r * r; + for (i = -r+1; i < r; i++) { + for (j = -r+1; j < r; j++) { + if (i*i + j*j >= r2) continue; + if (!image_set_px_c(image, x + i, y + j, color)) retval = 0; + } + } + return retval; +} + +int image_draw_square(Image image, int x, int y, int size, Color color) { + int retval = 1; + int i, j; + for (i = -size / 2; i <= size / 2; i++) { + for (j = -size / 2; j <= size / 2; j++) { + if (!image_set_px_c(image, x + i, y + j, color)) retval = 0; + } + } + return retval; +} \ No newline at end of file diff --git a/images/images.h b/images/images.h index 5d5beff..c647925 100644 --- a/images/images.h +++ b/images/images.h @@ -2,37 +2,46 @@ #define IMAGES_H typedef struct _color { - char r; - char g; - char b; + unsigned char r; + unsigned char g; + unsigned char b; + float alpha; } Color; typedef struct _image { - char** bitmap; + unsigned char** bitmap; int width; int height; } Image; -int image_new(int width, int height, Image* image); +// basic image manipulation -int image_save(Image* image, char* path); +int image_new(int width, int height, Image* image); -int image_set_px(Image* image, int x, int y, int r, int g, int b); -int image_set_px_c(Image* image, int x, int y, Color* color); +int image_set_px(Image image, int x, int y, int r, int g, int b); +int image_set_px_c(Image image, int x, int y, Color color); -int image_check_coords(Image* image, int x, int y); +int image_check_coords(Image image, int x, int y); -int image_destroy(Image* image); +int image_destroy(Image image); -int image_byte_size(Image *image); +// drawing +int image_draw_rect(Image image, int x1, int y1, int x2, int y2, Color color); +int image_draw_circ(Image image, int x, int y, int r, Color color); +int image_draw_square(Image image, int x, int y, int s, Color color); -int image_draw_rect(Image* image, int x1, int y1, int x2, int y2, Color* color); +Color color_new(int r, int g, int b); +Color color_new_alpha(int r, int g, int b, float alpha); +void print_color(Color c); +Color color_mix(Color c1, Color c2, float ratio); -Color* color_new(int r, int g, int b); +// bmp format specifics: +int image_save_bmp(Image image, char* path); #include "images.c" +#include "bmp-format.c" #endif \ No newline at end of file diff --git a/main.c b/main.c index d0121cc..3bb327f 100644 --- a/main.c +++ b/main.c @@ -2,37 +2,70 @@ #include #include "images/images.h" +void test_transparency(); +void test_4k_gradient(); + int main(int argc, char* argv[]) { + test_transparency(); + test_4k_gradient(); +} +void test_transparency() { Image img; - image_new(512,512, &img); + Color white = color_new(255,255,255); + Color green = color_new(0,255,0); + Color blue = color_new(30,50,210); + Color black = color_new(0,0,0); - Color* green = color_new(0,255,0); - Color* purple = color_new(125,17,249); + image_new(512, 512, &img); - image_draw_rect(&img, 255, 0, 512, 255, green); - image_draw_rect(&img, 0, 255, 255, 512, purple); + // make it white + image_draw_rect(img, 0, 0, 512, 512, white); - for (int i = 0; i < 255; i++) { - for (int j = 0; j < 255; j++) { - image_set_px(&img, i, j, i, 0, 0); - } + // draw some circs + blue.alpha = 0.5; + image_draw_circ(img, 255,255, 100, blue); + image_draw_circ(img, 255,155, 100, blue); + image_draw_circ(img, 255,355, 100, blue); + green.alpha = .6; + image_draw_circ(img, 255, 255, 12, green); + + // draw a couple of rects + black.alpha = 0.5; + white.alpha = 0.5; + image_draw_square(img, 200, 255, 111, black); + image_draw_square(img, 200, 255, 101, white); + + if (!image_save_bmp(img, "test-transparency.bmp")) { + printf("error writing file!\n"); + } else { + printf("writing finished\n"); } - for (int i = 0; i <= 256; i++) { - for (int j = 0; j <= 256; j++) { - image_set_px(&img, i + 255, j + 255, j, j, 255); + + image_destroy(img); +} + +void test_4k_gradient() { + printf("allocating image\n"); + Image img; + image_new(1920 * 4,1080 * 4, &img); + + printf("writing pixies\n"); + + for (int i = 0; i < 1920 * 4; i++) { + for (int j = 0; j < 1080 * 4; j++) { + float color = (j / (1080.0f * 4)) * 255; + image_set_px(img, i, j, (int) color, 255, 255); } } - printf("Writing file to /home/anton/projects/mona/chaos/test.bmp\n"); + printf("writing file to disk\n"); - if (!image_save(&img, "/home/anton/projects/mona/chaos/test.bmp")) { - printf("Error writing file!\n"); + if (!image_save_bmp(img, "test-4k.bmp")) { + printf("error writing file!\n"); } else { - printf("Wrote file successfully\n"); + printf("writing finished\n"); } - image_destroy(&img); - - free(green); - free(purple); + image_destroy(img); + printf("image destroyed\n"); } \ No newline at end of file