/********************************************* * Description - Convert Farbfeld images to VNM * Author - Vilyaem * Date - May 03 2024 * *******************************************/ /*----------PREPROCESSOR----------*/ #include #include #define MAXRES 512 /*----------DATA STRUCTURES----------*/ /*color*/ typedef struct { uint8_t r; uint8_t g; uint8_t b; } Color; /*----------GLOBALS----------*/ Color palette[16] = { {0, 0, 0}, /*#000000 (Black)*/ {0, 0, 170}, /*#0000AA (Blue)*/ {0, 170, 0}, /*#00AA00 (Green)*/ {0, 170, 170}, /*#00AAAA (Cyan)*/ {170, 0, 0}, /*#AA0000 (Red)*/ {170, 0, 170}, /*#AA00AA (Magenta)*/ {170, 79, 0}, /*#AA5500 (Brown)*/ {170, 170, 170}, /*#AAAAAA (Light Gray)*/ {79, 79, 79}, /*#555555 (Dark Gray)*/ {79, 79, 255}, /*#5555FF (Light Blue)*/ {79, 255, 79}, /*#55FF55 (Light Green)*/ {79, 255, 255}, /*#55FFFF (Light Cyan)*/ {255, 79, 79}, /*#FF5555 (Light Red)*/ {255, 79, 255}, /*#FF55FF (Light Magenta)*/ {255, 255, 79}, /*#FFFF55 (Yellow)*/ {255, 255, 255} /*#FFFFFF (White)*/ }; int i; /*----------FUNCTIONS----------*/ /********************************************* * Description - Find closest colour in the palette * Author - Vilyaem * Date - May 03 2024 * *******************************************/ uint8_t findClosestColor(Color pixel) { uint8_t closestColor; int minDistance; closestColor = 0; minDistance = 255 * 255 * 3; /* Initialize with max distance value*/ for (i = 0; i < 16; i++) { int dr; int dg; int db; int distance; dr = pixel.r - palette[i].r; dg = pixel.g - palette[i].g; db = pixel.b - palette[i].b; distance = dr * dr + dg * dg + db * db; if (distance < minDistance) { minDistance = distance; closestColor = i; } } return closestColor; } /********************************************* * Description - Main * Author - Vilyaem * Date - May 03 2024 * *******************************************/ int main(int argc, char* argv[]) { uint32_t width; uint32_t height; FILE* output; FILE* input; char magic[8]; Color prevPixel = {0,0,0}; uint8_t colorCount; if (argc != 3) { printf("Usage: %s input_image.farbfeld output_image.rle\n", argv[0]); return 1; } input = fopen(argv[1], "rb"); if (!input) { puts("Error: Unable to open input file.\n"); return 1; } /*Reading header*/ fread(magic, 1, 8, input); /*Forced width and height*/ width = MAXRES; height = MAXRES; /*Output the RLE header*/ output = fopen(argv[2], "wb"); fputc('V', output); /* Magic number*/ fputc(width / 8, output); /* Actual width*/ fputc(height / 8, output); /* Actual height*/ /*Read and convert each pixel*/ colorCount = 1; for (i = 0; i < (int)width * (int)height; i++) { uint16_t rgba[4]; uint8_t currentColor; Color pixel; fread(rgba, sizeof(uint16_t), 4, input); /*pixel = (Color){rgba[0] >> 8, rgba[1] >> 8, rgba[2] >> 8};*/ pixel.r = rgba[0] >> 8; pixel.g = rgba[1] >> 8; pixel.b = rgba[2] >> 8; currentColor = findClosestColor(pixel); if (currentColor == findClosestColor(prevPixel) && colorCount < 64) { /*dont make V and A characters and break files!*/ colorCount++; } else { fputc(findClosestColor(prevPixel), output); fputc(colorCount, output); prevPixel = pixel; colorCount = 1; } } /*Output the last color run*/ if (colorCount > 0) { fputc(findClosestColor(prevPixel), output); fputc(colorCount, output); } fclose(input); fclose(output); puts("Conversion complete.\n"); return 0; }