145 lines
3.3 KiB
C
145 lines
3.3 KiB
C
#define STB_IMAGE_IMPLEMENTATION
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#define STBI_FAILURE_USERMSG
|
|
|
|
#include "stb_image.h"
|
|
#include "stb_image_write.h"
|
|
|
|
/*
|
|
0 - simple
|
|
balanced
|
|
1 - nomin
|
|
average of two largest channels, bias towards darker shades, use if unsure
|
|
2 - nomax
|
|
makes image brighter
|
|
3 - twist
|
|
results in a specific style. largest banding potential, reduce strength (2024 update I don't remember how I came up with that)
|
|
*/
|
|
#define LUMINANCE_METHOD 1
|
|
|
|
/*
|
|
less is more (literally). Accepts decimals.
|
|
go below 1 = regret
|
|
negative causes b&w (although it does not colorize already b&w images)
|
|
0 crashes
|
|
*/
|
|
#define VIBRANCE_STRENGTH 1.1
|
|
|
|
/*
|
|
this is to make things more natural but sometimes does the opposite so toggle if u get weird things (I have a fix in mind tho) (2024 update not anymore)
|
|
basically darkens too bright things and vice versa
|
|
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;
|
|
|
|
unsigned char *img = stbi_load(input, &width, &height, &channels, 3);
|
|
|
|
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;
|
|
}
|