Files
ZiFi/_src/bmp2sxg_src/bmp2sxg.c
T
2026-08-31 21:04:48 +03:00

450 lines
14 KiB
C

/*Understand, Correct, Improve ___
________/| _________________/\__/\____/ /_____
\ ____/ |/ __/ / / __ / \/ \ \ / __/
| __/ /\__ \ / __ \ / \ _/ \
|___\ \__\____ //__/\_____/\ /__/\ /_____/
`-------------\/------breeze-\ /crew-\/------'
\/
BMP to SXG (Speccy eXtended Graphics) [PentEvo 256]
----------------------------------------------------------
Written by breeze \ fishbone crew | http://fishbone.untergrund.net/
breeze@tut.by
18.02.2015
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//---------------------------------------------------------------------------------------------
void printBits(char number){
char *bitsStr = "00000000\0";
for (int pos=8; pos>0; pos--) {
if(number > 0){
bitsStr[pos-1] = '0' + (number%2);
number = number/2;
} else {
bitsStr[pos-1] = '0';
}
}
printf(bitsStr);
}
unsigned int fileLength(FILE *f) {
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
void printStrint (char *str) {
for (int i=0; str[i] != '\0'; i++){
printf ("%c", str[i]);
}
}
bool testHex (char testChar) {
bool valid = false;
if ((testChar > 0x2F && testChar < 0x39) || (testChar > 0x40 && testChar < 0x47)) {
valid = true;
}
return valid;
}
//---------------------------------------------------------------------------------------------
int main (int argc, char *argv[]) {
char *filename = NULL;
bool debugMode = false;
bool enableShim = true;
bool wrongParams = false;
unsigned char sxgBgColor = 0;
if ((argc > 1) && (argv[1][0] != '-')) {
filename = argv[1];
++argv;
--argc;
}
while ((argc > 1) && (argv[1][0] == '-' && argv[1][1] == '-')) {
//printf("arg %d = param %s\n", argc, argv[1]);
if (strcmp (argv[1], "--debug") == 0) {
debugMode = true;
} else if (strcmp (argv[1], "--64") == 0) {
enableShim = false;
} else if (strcmp (argv[1], "--bg") == 0) {
if (argv[2] != NULL) {
//printf("arg %d = param %s, param2 %s\n", argc, argv[1], argv[2]);
//sxgBgColor = argv[2];
sxgBgColor = (unsigned char)strtol(argv[2], NULL, 10);
} else {
wrongParams = true;
}
}
++argv;
--argc;
}
// \033[22;30m - black
// \033[22;31m - red
// \033[22;32m - green
// \033[22;33m - brown
// \033[22;34m - blue
// \033[22;35m - magenta
// \033[22;36m - cyan
// \033[22;37m - gray
// \033[01;30m - dark gray
// \033[01;31m - light red
// \033[01;32m - light green
// \033[01;33m - yellow
// \033[01;34m - light blue
// \033[01;35m - light magenta
// \033[01;36m - light cyan
// \033[01;37m - white
printf("\nBMP to SXG (Speccy eXtended Graphics) v0.4 (alpha) 18 Feb 2015\n");
printf("-----------------------------------------------------------------------------------\n");
printf("Written by breeze\\fishbone crew | fishbone@speccy.su | http://fishbone.untergrund.net/\n");
printf("\n");
if (filename == NULL || wrongParams) {
printf("Usage: bmp2sxg <filename> [commands]\n");
printf("Commands:\n");
printf(" --debug enable output debug information (default disabled)\n");
printf(" --64 cut palette to atm 64 colors limit (default disabled)\n");
printf(" --bg nn set background color. where nn number from palette (default #00)\n");
} else {
printf("Debug: ");
if (debugMode) {
printf("Enabled\n");
} else {
printf("Disabled\n");
}
printf("Full colors: ");
if (enableShim) {
printf("Enabled\n");
} else {
printf("Disabled\n");
}
printf("Work file: %s ", filename);
FILE *readfile = fopen(filename, "rb");
if (readfile != NULL) {
unsigned int filelen = fileLength(readfile);
if (filelen > 0) {
printf("(%i bytes)\n", filelen);
void *fileContent = malloc( filelen + 1 );
fread(fileContent, filelen, 1, readfile);
fclose(readfile);
memcpy ((void *)((unsigned int)fileContent + filelen), "\0", 1);
printf ("File analizing... ");
unsigned char *bmpData = (unsigned char *)fileContent;
unsigned char *beginData = (unsigned char *)fileContent;
if (*(bmpData) == 'B' && *(bmpData+1) == 'M') {
bmpData += 2;
printf("BMP format detected!\n");
unsigned long bmpSize = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
bmpData += 4; // reserved 4 bytes
unsigned long imageStart = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long headerSize = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpWidth = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpHeigth = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned short bmpLayers = *(bmpData) + (*(bmpData+1)*256);
bmpData += 2;
unsigned short bmpBits = *(bmpData) + (*(bmpData+1)*256);
bmpData += 2;
unsigned long bmpCompressType = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpCompressSize = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpHorizontal = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpVertical = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpColors = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
unsigned long bmpColorsActive = (*(bmpData) + (*(bmpData+1)*256)) + (*(bmpData+2) + (*(bmpData+3)*256))*256;
bmpData += 4;
printf("\nBMP header:\n");
printf("---------------------------------\n");
printf (" file size: %d bytes\n", bmpSize);
printf (" image width: %d px\n", bmpWidth);
printf (" image heigth: %d px\n", bmpHeigth);
printf (" image planes: %d\n", bmpLayers);
printf (" bits/pixel: %d\n", bmpBits);
//printf (" compress type: %d (0-NO, 1-RLE8, 2 - RLE4)\n", bmpCompressType);
printf (" compress type: %d ", bmpCompressType);
switch (bmpCompressType) {
case 0:
printf ("(none)");
break;
case 1:
printf ("(RLE 8-bit/pixel)");
break;
case 2:
printf ("(RLE 4-bit/pixel)");
break;
case 3:
printf ("(Bit field or Huffman 1D compression for BITMAPCOREHEADER2)");
break;
case 4:
printf ("(JPEG or RLE-24 compression for BITMAPCOREHEADER2)");
break;
case 5:
printf ("(PNG)");
break;
case 6:
printf ("(Bit field)");
break;
default:
printf ("(unknown)");
}
printf ("\n");
printf (" image size: %d bytes\n", bmpCompressSize);
printf (" x pixels per meter: %d\n", bmpHorizontal);
printf (" y pixels per meter: %d\n", bmpVertical);
printf (" colors in color table: %d\n", bmpColors);
printf (" important color count: %d\n\n", bmpColorsActive);
if (bmpCompressType == 0) {
printf("BMP palette:\n");
printf("---------------------------------\n");
unsigned char realColorz = bmpColors;
if ( realColorz == 0 ) {
realColorz = bmpBits * bmpBits;
}
if (realColorz > 0) {
unsigned char colorz[realColorz*2];
printf ("BMP use calculated colors: %d\n\n", realColorz);
if (debugMode) {
printf (" No # R G B R G B pentevo xRRrrrGG gggBBbbb\n");
}
int index = 0;
for (int i = 0; i<realColorz; i++) {
if (debugMode) {
printf("BMP color %3d[#%02X] ",i,i);
}
unsigned char b = *(bmpData);
bmpData++;
unsigned char g = *(bmpData);
bmpData++;
unsigned char r = *(bmpData);
bmpData++;
unsigned char x = *(bmpData); // reserved
bmpData++;
if (debugMode) {
printf("[#%02X,#%02X,#%02X] -> ",r,g,b);
}
unsigned char colorCodeL = 0;
unsigned char colorCodeH = 0;
r = (r/10.6 + 0.5);
g = (g/10.6 + 0.5);
b = (b/10.6 + 0.5);
if (enableShim) {
colorCodeL = (b & 31) | ((g & 7)<<5);
colorCodeH = ((r & 31)<<2) | ((g & 31)>>3);
} else {
colorCodeL = (b & 24);
colorCodeH = ((r & 24)<<2) | ((g & 24)>>3);
}
if (debugMode) {
printf("%3d,%3d,%3d ",r,g,b);
printf("-> %3d,%3d[#%02X%02X] ", colorCodeH, colorCodeL, colorCodeH, colorCodeL);
printBits(colorCodeH);
printf(" ");
printBits(colorCodeL);
printf("\n");
}
colorz[index] = colorCodeL;
index++;
colorz[index] = colorCodeH;
index++;
}
printf("\nBMP Bitmap data...\n");
printf("---------------------------------\n");
// bmpBits 1 - bitmap is monochrome
// bmpBits 4 - bitmap has a maximum of 16 colors
// bmpBits 8 - bitmap has a maximum of 256 colors
// bmpBits 16 - bitmap has a maximum of 65536 colors
// bmpBits 32 - bitmap has a maximum of 16777216 colors
printf("Bitmap bits - %d \n", bmpBits);
if (bmpBits == 4 || bmpBits == 8) {
unsigned long dataLen = ( bmpWidth * bmpHeigth );
if ( dataLen > 0 ) {
unsigned char *bmpImageData=(unsigned char *)(beginData+imageStart);
unsigned char *memImageData = (unsigned char *)malloc(dataLen);
unsigned char *workImageData = (unsigned char *)(memImageData);
unsigned long workWidth = bmpWidth;
if (bmpBits == 4) {
workWidth = bmpWidth / 2;
if (bmpWidth % 2 >=5 ) {
workWidth++;
}
dataLen = ( workWidth * bmpHeigth );
}
printf("workWidth - %d\n", workWidth);
printf("Bitmap data length - %d bytes\n", dataLen);
// int delta = workWidth % 4;
int rowSize = (bmpBits * bmpWidth + 31) / 32 * 4;
printf("Bitmap rowSize - %d bytes\n", rowSize);
for (int y = bmpHeigth - 1; y >= 0; y-- ) {
// for (int y = 0; y <bmpHeigth; y++ ) {
for (int x = 0; x < workWidth; x++){
unsigned char colorPixel = *(bmpImageData + x + ( y * rowSize));
*workImageData = colorPixel;
workImageData++;
if (debugMode) {
printf("#%02X,",colorPixel);
}
}
if (debugMode) {
printf("\n");
}
}
unsigned char colorzFinal[realColorz*2];
for (int i=0; i<realColorz*2; i++) {
colorzFinal[i] = colorz[i];
}
// +#0000 #04 #7f+"SXG" - 4 байта сигнатура, что это формат файла
// +#0004 #01 1 байт версия формата
// +#0005 #01 1 байт цвет фона (для очистки)
// +#0006 #01 1 байт тип упаковки данных (#00 - данные не пакованы)
// +#0007 #01 1 байт формат изображения (1 - 16ц, 2 - 256ц)
// +#0008 #02 2 байта ширина изображения
// +#000a #02 2 байта высота изображения
// (что бы можно было добавить ещё параметры)
// +#000c #02 смещение от текущего адреса до начала данных палитры
// +#000e #02 смещение от текущего адреса до начала данных битмап
// Начало данных палитры
// +#0010 #0200 512 байт палитра
// Начало данных битмап
// +#0210 #xxxx данные битмап
char *saveFileName = strtok(filename, ".");
saveFileName = strcat(saveFileName,".sxg");
FILE *writeSxgFile = fopen(saveFileName, "wb");
if (writeSxgFile != NULL) {
unsigned char *sxgId = "\x7FSXG";
fwrite(sxgId, 1, 4, writeSxgFile);
unsigned char *sxgVer = "\x02";
fwrite(sxgVer, 1, 1, writeSxgFile);
//unsigned char *sxgBg = "\x00";
fwrite(&sxgBgColor, 1, 1, writeSxgFile);
unsigned char *sxgPack = "\x00";
fwrite(sxgPack, 1, 1, writeSxgFile);
unsigned char sxgType = 1;
if (bmpBits > 4) {
sxgType = 2;
}
fwrite(&sxgType, 1, 1, writeSxgFile);
short int sxgWidth = (short int)bmpWidth;
short int sxgHeigth = (short int)bmpHeigth;
fwrite(&bmpWidth, 1, sizeof(short int), writeSxgFile);
fwrite(&bmpHeigth, 1, sizeof(short int), writeSxgFile);
short int palStart = 2;
fwrite(&palStart, 1, sizeof(short int), writeSxgFile);
short int palSize = realColorz*2;
fwrite(&palSize, 1, sizeof(short int), writeSxgFile);
fwrite(colorzFinal, 1, palSize, writeSxgFile);
workImageData = memImageData;
unsigned long writeLen = dataLen;
fwrite(workImageData, 1, writeLen, writeSxgFile);
} else {
printf ("Error: Can't write file: %s", saveFileName);
}
free (memImageData);
} else {
printf("Error: Wrong bitmap legth!\n");
return 1;
}
} else {
printf("Error: support only 16 & 256 colors bmp!\n");
return 1;
}
} else {
printf("Error: Wrong BMP palette.\n");
return 1;
}
} else {
printf("Error: Compressed file not supported yet.\n");
return 1;
}
} else {
printf("Error: Wrong format of file - %s\n", filename);
return 1;
}
free (fileContent);
} else {
printf ("Error: Wrong size of file - %s\n", filename);
return 1;
}
} else {
printf ("Error: Can't opening file - %s\n", filename);
return 1;
}
}
return 0;
}