450 lines
14 KiB
C
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;
|
|
}
|