107 lines
3.2 KiB
C
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;
|
|
}
|