157 行
3.9 KiB
C
157 行
3.9 KiB
C
/*********************************************
|
|
* Description - Convert Farbfeld images to VNM
|
|
* Author - Vilyaem
|
|
* Date - May 03 2024
|
|
* *******************************************/
|
|
|
|
/*----------PREPROCESSOR----------*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
#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;
|
|
}
|