enhancer/main.c

144 lines
3.3 KiB
C
Raw Normal View History

2024-07-16 13:44:28 +02:00
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STBI_FAILURE_USERMSG
#include "stb_image.h"
#include "stb_image_write.h"
/*
2024-08-13 15:30:32 +02:00
0 - balanced
1 - average of two largest channels, bias towards darker shades, use if unsure
2 - makes image brighter
3 - ??? (lots of banding so reduce strength)
2024-07-16 13:44:28 +02:00
*/
#define LUMINANCE_METHOD 1
/*
2024-08-13 15:30:32 +02:00
1 is the minimum, going below 1 makes surprising effects
the higher value the less effect it has
so when I say "reduce strength" I mean "increase the value"
2024-07-16 13:44:28 +02:00
*/
#define VIBRANCE_STRENGTH 1.1
/*
2024-08-13 15:30:32 +02:00
if a pixel goes below 0% or above 100% basically subtract the difference
so -10% becomes 10% and 110% becomes 90%
this was supposed to fix clipping but messes up colors (I remember I had in mind a fix but I don't remember it)
2024-07-16 13:44:28 +02:00
uncomment to enable
*/
//#define BETTER_CLAMP
const static inline int max(int a, int b) {
return a > b ? a : b;
}
const static inline int max3(int a, int b, int c) {
int ab = max(a, b);
return ab > c ? ab : c;
}
const static inline int min(int a, int b) {
return a < b ? a : b;
}
const static inline int min3(int a, int b, int c) {
int ab = min(a, b);
return ab < c ? ab : c;
}
#ifdef BETTER_CLAMP
const static inline int cdiff(int n, int min, int max) {
if (n > max)
return max - (n - max);
else if (n < min) {
return min + (min - n);
}
return n;
}
const static inline int clamp(int n, int min, int max) {
return cdiff(n, min, max);
} // I don't know if const static inline was needed
#else
const static inline int clamp(int n, int min, int max) {
return n > max ? max : (n < min ? min : n);
}
#endif
void vibrancer(unsigned char *pixel) {
int r = pixel[0],
g = pixel[1],
b = pixel[2];
// TODO remove unnecessary calculations
int min_rgb = min3(r, g, b);
int max_rgb = max3(r, g, b);
int sum = r + g + b;
int m;
if (LUMINANCE_METHOD == 3) // twist
m = 3*sum - 4*(min_rgb + max_rgb);
else if (LUMINANCE_METHOD == 2) // nomax
m = (sum - max_rgb) / 2;
else if (LUMINANCE_METHOD == 1) // nomin
m = (sum - min_rgb) / 2;
else // simple
m = sum / 3;
r -= (m - r) / VIBRANCE_STRENGTH;
g -= (m - g) / VIBRANCE_STRENGTH;
b -= (m - b) / VIBRANCE_STRENGTH;
pixel[0] = clamp(r, 0, 255);
pixel[1] = clamp(g, 0, 255);
pixel[2] = clamp(b, 0, 255);
}
int main(int argc, char **argv) {
if (VIBRANCE_STRENGTH == 0) {
printf("VIBRANCE_STRENGTH cannot be zero");
return 1;
}
char* input = argv[1];
char* output = argv[2];
if (argc < 3) {
printf("Please specify input and output files\n");
return 2;
}
int width, height, channels;
2024-08-04 12:03:56 +02:00
unsigned char *img = stbi_load(input, &width, &height, &channels, 0);
2024-08-04 12:05:34 +02:00
//printf("Width: %d, Height: %d, Channels: %d\n", width, height, channels);
2024-07-16 13:44:28 +02:00
if (img == NULL) {
printf("Error loading image\n");
printf("%s\n", stbi_failure_reason());
return 1;
}
if (channels < 3) {
printf("Not enough channels (%d)", channels);
return 1;
}
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
unsigned char *pixel = img + (y * width + x) * channels;
vibrancer(pixel);
}
}
stbi_write_png(output, width, height, channels, img, width * channels);
return 0;
}