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
|
|
|
*/
|
2024-09-12 19:55:33 +02:00
|
|
|
#define VIBRANCE_STRENGTH 1.5
|
2024-07-16 13:44:28 +02:00
|
|
|
|
|
|
|
/*
|
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;
|
|
|
|
}
|