#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]; printf("%d %d %d\n", r, g, b); // 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, 0); printf("Width: %d, Height: %d, Channels: %d\n", width, height, channels); 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