Files
TDT4200/exercise0/main.c
2025-08-25 11:52:35 +02:00

107 lines
3.2 KiB
C

#include "bitmap.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#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);
// change colors
modulo_scale_channel(image, 2, 2);
modulo_scale_channel(image, 1, 0.420);
modulo_scale_channel(image, 0, 0.69);
// 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;
}