diff --git a/exercise0/main b/exercise0/main new file mode 100755 index 0000000..9d728cb Binary files /dev/null and b/exercise0/main differ diff --git a/exercise0/main.c b/exercise0/main.c index 90cb014..2930b5d 100644 --- a/exercise0/main.c +++ b/exercise0/main.c @@ -1,18 +1,105 @@ #include "bitmap.h" +#include #include #include #define XSIZE 2560 // Size of before image #define YSIZE 2048 +#define INDEX(row, col) ((row) * XSIZE * 3 + (col) * 3) + +// scale a color channel by a factor from an rgb-pixel array, +// - channel = 0: scales red +// - channel = 1: scales green +// - channel = 2: scales blue +void modulo_scale_channel(uchar *data, int channel, float factor) { + if (channel > 2 || channel < 0) + return; + for (int row = 0; row < YSIZE; row++) { + for (int col = 0; col < XSIZE; col++) { + int i = INDEX(row, col); + // `2 - channel` because we get data as bgr, not rgb + data[i + 2 - channel] = (uchar)(data[i] * factor) % 256; + } + } +} + +// scale the entire image data by a given factor in both width and height. +void scale(uchar **data, int factor) { + uchar *scaled_data = calloc(XSIZE * YSIZE * 3 * factor * factor, 1); + for (int row = 0; row < YSIZE * factor; row++) { + for (int col = 0; col < XSIZE * factor; col++) { + int old = INDEX(row / factor, col / factor); + int new = INDEX(row * factor, col); // `* factor` for new row size. + for (int c = 0; c < 3; c++) // each color channel. + scaled_data[new + c] = (*data)[old + c]; + } + } + free(*data); + *data = scaled_data; +} + +// rotate the image data by 180 degrees. +void rotate(uchar *data) { + for (int row = 0; row < YSIZE; row++) { + for (int col = 0; col < XSIZE; col++) { + int old = INDEX(row, col); + int new = INDEX(YSIZE - row - 1, XSIZE - col - 1); // `- 1` for 0-index + + // swap all 3 color channels using the XOR swap algorithm to avoid temp. + // `i < j` to only do the swap once for the lower triangle. + if (old < new) { + for (int c = 0; c < 3; c++) { + data[old + c] = data[old + c] ^ data[new + c]; + data[new + c] = data[old + c] ^ data[new + c]; + data[old + c] = data[old + c] ^ data[new + c]; + } + } + } + } +} + +uchar color(int row, int col) { + // reverse row to apply gradient from upper left + row = YSIZE - row - 1; + // AI: combine row and col and scale with width and height + return (uchar)(((float)(row + col) / (XSIZE + YSIZE - 2)) * 255); +} + +// apply a gradient from upper left to lower right +void gradient(uchar *data, uchar (*color)(int, int), float alpha) { + for (int row = 0; row < YSIZE; row++) { + for (int col = 0; col < XSIZE; col++) { + int i = INDEX(row, col); + for (int c = 0; c < 3; c++) { + // AI: blend color channel with color of position and given alpha value + float t = alpha + (1.0f - alpha) * color(row, col) / 255.0f; + data[i + c] = (uchar)(data[i + c] * t); + } + } + } +} + int main(void) { uchar *image = calloc(XSIZE * YSIZE * 3, 1); // Three uchars per pixel (RGB) readbmp("before.bmp", image); - // Alter the image here - ; + // change colors + modulo_scale_channel(image, 2, 2); + modulo_scale_channel(image, 1, 0.420); + modulo_scale_channel(image, 0, 0.69); - savebmp("after.bmp", image, XSIZE, YSIZE); + // apply gradient + gradient(image, &color, 0.05); + + // rotate by 180 degrees + rotate(image); + + // scale image + const int factor = 2; + scale(&image, factor); + + savebmp("after.bmp", image, XSIZE * factor, YSIZE * factor); free(image); return 0; diff --git a/flake.nix b/flake.nix index 36e4dbc..63a4851 100644 --- a/flake.nix +++ b/flake.nix @@ -23,6 +23,7 @@ typstyle zip unzip + feh ]; shellHook = '' echo welcome!