Licar/assets/encodeImage.c
2024-07-29 17:42:40 +02:00

171 lines
3.7 KiB
C

/**
Program for converting an outputImage to C array for Licar. The input
outputImage must be 64x64, in PPM format (tested with the one exported by
GIMP). Pass the outputImage on standard input, the array will be output on
standard output and preview PPM outputImage will be saved. The array is saved
in 565 indexed mode: first 512 bytes is the 565 palette, then 64x64 1 byte
indices follow.
*/
#include <stdio.h>
#define IMG_SIZE 64
int inChar = 0;
int state = 0;
unsigned int inputPixels[IMG_SIZE * IMG_SIZE]; // 565 format
unsigned int palette[256];
unsigned char outputImage[IMG_SIZE * IMG_SIZE];
unsigned int rgbTo565(unsigned char red, unsigned char green,
unsigned char blue)
{
return (((unsigned int) (red / 8)) << 11) |
(((unsigned int) (green / 4)) << 5) | (blue / 8);
}
void rgbFrom565(unsigned int colorIndex, unsigned char *red,
unsigned char *green, unsigned char *blue)
{
unsigned char value = colorIndex >> 11;
*red = value != 31 ? value * 8 : 255;
value = (colorIndex >> 5) & 0x3f;
*green = value != 63 ? value * 4 : 255;
value = colorIndex & 0x1f;
*blue = value != 31 ? value * 8 : 255;
}
unsigned char findClosesPaletteColor(unsigned int color)
{
unsigned char r, g, b;
unsigned int bestDist = 0xffff;
unsigned int bestIndex = 0;
rgbFrom565(color,&r,&g,&b);
for (int j = 0; j < 256; ++j)
{
unsigned char r2, g2, b2;
unsigned int d;
rgbFrom565(palette[j],&r2,&g2,&b2);
d = (r > r2 ? r - r2 : (r2 - r)) +
(g > g2 ? g - g2 : (g2 - g)) +
(b > b2 ? b - b2 : (b2 - b));
if (d == 0)
return j;
else if (d < bestDist)
{
bestIndex = j;
bestDist = d;
}
}
return bestIndex;
}
void savePreview(void)
{
FILE *f = fopen("preview.ppm","w");
fwrite("P6\n64\n64\n255\n",13,1,f);
for (int i = 0; i < IMG_SIZE * IMG_SIZE; ++i)
{
unsigned char color[3];
rgbFrom565(palette[outputImage[i]],color,color + 1,color + 2);
fwrite(color,3,1,f);
}
fclose(f);
}
int main(void)
{
while (state < 4) // just skip beyond the last field ("255<newline>")
{
inChar = getchar();
switch (state)
{
case 0: state = inChar == '2' ? 1 : 0; break;
case 1: state = inChar == '5' ? 2 : 0; break;
case 2: state = inChar == '5' ? 3 : 0; break;
case 3: state = inChar == 10 ? 4 : 0; break;
default: break;
}
}
for (int i = 0; i < 256; ++i) // start with 332 palette
palette[i] = ((i >> 5) << 13) | (((i >> 2) & 0x07) << 8) | ((i & 0x3) << 3);
for (int i = 0; i < IMG_SIZE * IMG_SIZE; ++i)
{
unsigned int r, g, b, color;
r = getchar();
g = getchar();
b = getchar();
color = rgbTo565(r,g,b);
inputPixels[i] = color;
// we're constructing the palette by bumping common colors higher up
for (int j = 0; j < 256; ++j)
if ((palette[j] & 0xf7de) == (color & 0xf7de)) // approximate comparison
{
if (j != 0)
{
// bump the color to higher place
palette[j] = palette[j - 1];
palette[j - 1] = color;
}
break;
}
else if (j == 255)
palette[255 - (i % 16)] = color;
}
for (int i = 0; i < IMG_SIZE * IMG_SIZE; ++i)
outputImage[i] = findClosesPaletteColor(inputPixels[i]);
savePreview();
for (int j = 0; j < 32; ++j)
{
printf(" ");
for (int i = 0; i < 8; ++i)
{
unsigned int color = palette[j * 8 + i];
printf("0x%02x,0x%02x,",color & 0xff,color >> 8);
}
putchar('\n');
}
printf(" ");
for (int i = 0; i < IMG_SIZE * IMG_SIZE; ++i)
{
printf("0x%02x",outputImage[i]);
if (i != IMG_SIZE * IMG_SIZE - 1)
{
putchar(',');
if ((i + 1) % 16 == 0)
printf("\n ");
}
}
return 0;
}