Refactor of Load_BMP() + support of OS/2 BMP

This commit is contained in:
Thomas Bernard 2018-01-17 00:53:01 +01:00
parent ee11079b86
commit c2c36849b5

View File

@ -1379,16 +1379,18 @@ void Test_BMP(T_IO_Context * context)
{ {
if ( header.Signature[0]=='B' && header.Signature[1]=='M' if ( header.Signature[0]=='B' && header.Signature[1]=='M'
&& header.Size_2==40 && (header.Size_2==40 /* WINDOWS */ || header.Size_2==12 /* OS/2 */)
&& header.Width && header.Height ) && header.Width && header.Height )
{
File_error=0; File_error=0;
} }
}
fclose(file); fclose(file);
} }
} }
// Find the 8 important bits in a dword // Find the 8 important bits in a dword
byte Bitmap_mask(dword pixel, dword mask) static byte Bitmap_mask(dword pixel, dword mask)
{ {
byte result; byte result;
int i; int i;
@ -1428,141 +1430,102 @@ byte Bitmap_mask(dword pixel, dword mask)
return result << (8-bits_found); return result << (8-bits_found);
} }
// -- Charger un fichier au format BMP -------------------------------------- void Load_BMP_Palette(T_IO_Context * context, FILE * file, unsigned int nb_colors, int is_rgb24)
void Load_BMP(T_IO_Context * context)
{ {
char filename[MAX_PATH_CHARACTERS]; byte local_palette[256*4]; // R,G,B,0 or RGB
FILE *file; unsigned int i, j;
T_BMP_Header header;
byte * buffer;
word index;
byte local_palette[256][4]; // R,G,B,0
word nb_colors = 0;
short x_pos;
short y_pos;
word line_size;
byte a,b,c=0;
long file_size;
byte negative_height;
Get_full_filename(filename, context->File_name, context->File_directory); if (Read_bytes(file,local_palette,nb_colors*(is_rgb24?3:4)))
File_error=0;
if ((file=fopen(filename, "rb")))
{
file_size=File_length_file(file);
if (Read_bytes(file,header.Signature,2)
&& Read_dword_le(file,&(header.Size_1))
&& Read_word_le(file,&(header.Reserved_1))
&& Read_word_le(file,&(header.Reserved_2))
&& Read_dword_le(file,&(header.Offset))
&& Read_dword_le(file,&(header.Size_2))
&& Read_dword_le(file,&(header.Width))
&& Read_dword_le(file,(dword *)&(header.Height))
&& Read_word_le(file,&(header.Planes))
&& Read_word_le(file,&(header.Nb_bits))
&& Read_dword_le(file,&(header.Compression))
&& Read_dword_le(file,&(header.Size_3))
&& Read_dword_le(file,&(header.XPM))
&& Read_dword_le(file,&(header.YPM))
&& Read_dword_le(file,&(header.Nb_Clr))
&& Read_dword_le(file,&(header.Clr_Imprt))
)
{
switch (header.Nb_bits)
{
case 1 :
case 4 :
case 8 :
if (header.Nb_Clr)
nb_colors=header.Nb_Clr;
else
nb_colors=1<<header.Nb_bits;
break;
default:
File_error=1;
}
if (header.Height < 0)
{
negative_height=1;
header.Height = -header.Height;
}
else
{
negative_height=0;
}
if (!File_error)
{
Pre_load(context, header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE,0);
if (File_error==0)
{
if (Read_bytes(file,local_palette,nb_colors<<2))
{ {
if (Config.Clear_palette) if (Config.Clear_palette)
memset(context->Palette,0,sizeof(T_Palette)); memset(context->Palette,0,sizeof(T_Palette));
// On peut maintenant transférer la nouvelle palette
for (index=0; index<nb_colors; index++) // We can now load the new palette
for (i=0, j=0; i<nb_colors; i++)
{ {
context->Palette[index].R=local_palette[index][2]; context->Palette[i].B=local_palette[j++];
context->Palette[index].G=local_palette[index][1]; context->Palette[i].G=local_palette[j++];
context->Palette[index].B=local_palette[index][0]; context->Palette[i].R=local_palette[j++];
if (!is_rgb24) j++;
} }
}
else
{
File_error=1;
}
}
context->Width=header.Width; void Load_BMP_Pixels(T_IO_Context * context, FILE * file, unsigned int compression, unsigned int nbbits, int top_down, const dword * mask)
context->Height=header.Height; {
unsigned int row_size;
unsigned int index;
short x_pos;
short y_pos;
byte * buffer;
byte value;
byte a,b,c=0;
if (fseek(file, header.Offset, SEEK_SET)) printf("Load_BMP_Pixels compression=%d nbbits=%d top_down=%d\n", compression, nbbits, top_down);
File_error=2; switch (compression)
switch (header.Compression)
{ {
case 0 : // Pas de compression case 0 : // Pas de compression
line_size=context->Width; case 3 :
x_pos=(32/header.Nb_bits); // x_pos sert de variable temporaire row_size = ((nbbits*context->Width + 31) >> 3) & ~3;
// On arrondit line_size au premier multiple de x_pos supérieur buffer = malloc(row_size);
if (line_size % x_pos)
line_size=((line_size/x_pos)*x_pos)+x_pos;
// On convertit cette taille en octets
line_size=(line_size*header.Nb_bits)>>3;
buffer=(byte *)malloc(line_size);
for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++) for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++)
{ {
short target_y; short target_y;
target_y = negative_height ? y_pos : context->Height-1-y_pos; target_y = top_down ? y_pos : context->Height-1-y_pos;
if (Read_bytes(file,buffer,line_size)) if (Read_bytes(file,buffer,row_size))
{
for (x_pos=0; x_pos<context->Width; x_pos++) for (x_pos=0; x_pos<context->Width; x_pos++)
switch (header.Nb_bits) {
switch (nbbits)
{ {
case 8 : case 8 :
Set_pixel(context, x_pos,target_y,buffer[x_pos]); value = buffer[x_pos];
break; break;
case 4 : case 4 :
if (x_pos & 1) value = (x_pos & 1) ? (buffer[x_pos>>1] & 0xF) : (buffer[x_pos>>1] >> 4);
Set_pixel(context, x_pos,target_y,buffer[x_pos>>1] & 0xF);
else
Set_pixel(context, x_pos,target_y,buffer[x_pos>>1] >> 4 );
break; break;
case 1 : case 1 :
if ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) value = ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) ? 1 : 0;
Set_pixel(context, x_pos,target_y,1); break;
else case 24:
Set_pixel(context, x_pos,target_y,0); Set_pixel_24b(context, x_pos,target_y,buffer[x_pos*3+2],buffer[x_pos*3+1],buffer[x_pos*3+0]);
break;
case 32:
{
dword pixel = ((dword *)buffer)[x_pos];
Set_pixel_24b(context, x_pos,target_y,Bitmap_mask(pixel,mask[0]),Bitmap_mask(pixel,mask[1]),Bitmap_mask(pixel,mask[2]));
}
break;
case 16:
{
word pixel = ((word *)buffer)[x_pos];
Set_pixel_24b(context, x_pos,target_y,Bitmap_mask(pixel,mask[0]),Bitmap_mask(pixel,mask[1]),Bitmap_mask(pixel,mask[2]));
}
break;
default:
value = 0;
}
if (nbbits <= 8)
Set_pixel(context, x_pos, target_y, value);
}
} }
else else
{
File_error=2; File_error=2;
} }
}
free(buffer); free(buffer);
buffer = NULL; buffer = NULL;
break; break;
case 1 : // Compression RLE 8 bits case 1 : // Compression RLE 8 bits
x_pos=0; x_pos=0;
y_pos=context->Height-1; y_pos=context->Height-1;
/*Init_lecture();*/ /*Init_lecture();*/
@ -1611,14 +1574,12 @@ void Load_BMP(T_IO_Context * context)
File_error=2; File_error=2;
} }
} }
/*Close_lecture();*/
break; break;
case 2 : // Compression RLE 4 bits case 2 : // Compression RLE 4 bits
x_pos=0; x_pos=0;
y_pos=context->Height-1; y_pos=context->Height-1;
/*Init_lecture();*/
if(Read_byte(file, &a)!=1 || Read_byte(file, &b) != 1) if(Read_byte(file, &a)!=1 || Read_byte(file, &b) != 1)
File_error =2; File_error =2;
while ( (!File_error) && ((a)||(b!=1)) ) while ( (!File_error) && ((a)||(b!=1)) )
@ -1668,132 +1629,158 @@ void Load_BMP(T_IO_Context * context)
} }
if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2;
} }
/*Close_lecture();*/
}
fclose(file);
}
else
{
fclose(file);
File_error=1;
}
}
}
else
{
// Image 16/24/32 bits
dword red_mask;
dword green_mask;
dword blue_mask;
if (header.Nb_bits == 16)
{
red_mask = 0x00007C00;
green_mask = 0x000003E0;
blue_mask = 0x0000001F;
}
else
{
red_mask = 0x00FF0000;
green_mask = 0x0000FF00;
blue_mask = 0x000000FF;
}
File_error=0;
context->Width=header.Width;
context->Height=header.Height;
Pre_load(context,header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE,1);
if (File_error==0)
{
switch (header.Compression)
{
case 3: // BI_BITFIELDS
if (!Read_dword_le(file,&red_mask) ||
!Read_dword_le(file,&green_mask) ||
!Read_dword_le(file,&blue_mask))
File_error=2;
break; break;
default: default:
break; Warning("Unknown compression type");
} }
if (fseek(file, header.Offset, SEEK_SET)) }
File_error=2;
// -- Charger un fichier au format BMP --------------------------------------
void Load_BMP(T_IO_Context * context)
{
char filename[MAX_PATH_CHARACTERS];
FILE *file;
T_BMP_Header header;
word nb_colors = 0;
long file_size;
byte negative_height; // top_down
byte true_color;
dword mask[3]; // R G B
Get_full_filename(filename, context->File_name, context->File_directory);
File_error=0;
if ((file=fopen(filename, "rb")))
{
file_size=File_length_file(file);
if (!(Read_bytes(file,header.Signature,2)
&& Read_dword_le(file,&(header.Size_1))
&& Read_word_le(file,&(header.Reserved_1))
&& Read_word_le(file,&(header.Reserved_2))
&& Read_dword_le(file,&(header.Offset))
&& Read_dword_le(file,&(header.Size_2))
))
{
File_error = 1;
} }
if (File_error==0) else
{
if (header.Size_2 == 40 /* WINDOWS */)
{
if (!(Read_dword_le(file,&(header.Width))
&& Read_dword_le(file,(dword *)&(header.Height))
&& Read_word_le(file,&(header.Planes))
&& Read_word_le(file,&(header.Nb_bits))
&& Read_dword_le(file,&(header.Compression))
&& Read_dword_le(file,&(header.Size_3))
&& Read_dword_le(file,&(header.XPM))
&& Read_dword_le(file,&(header.YPM))
&& Read_dword_le(file,&(header.Nb_Clr))
&& Read_dword_le(file,&(header.Clr_Imprt))
)) File_error = 1;
}
else if (header.Size_2 == 12 /* OS/2 */)
{
word tmp_width = 0, tmp_height = 0;
if (Read_word_le(file,&tmp_width)
&& Read_word_le(file,&tmp_height)
&& Read_word_le(file,&(header.Planes))
&& Read_word_le(file,&(header.Nb_bits)))
{
header.Width = tmp_width;
header.Height = tmp_height;
header.Compression = 0;
header.Size_3 = 0;
header.XPM = 0;
header.YPM = 0;
header.Nb_Clr = 0;
header.Clr_Imprt = 0;
}
else
File_error = 1;
}
else
{
Warning("Unknown BMP type");
File_error = 2;
}
}
if (File_error == 0)
{ {
switch (header.Nb_bits) switch (header.Nb_bits)
{ {
// 24bit bitmap case 1 :
case 4 :
case 8 :
true_color = 0;
if (header.Nb_Clr)
nb_colors=header.Nb_Clr;
else
nb_colors=1<<header.Nb_bits;
break;
default: default:
case 24: true_color = 1;
line_size=context->Width*3; }
x_pos=(line_size % 4); // x_pos sert de variable temporaire
if (x_pos>0)
line_size+=(4-x_pos);
buffer=(byte *)malloc(line_size); if (header.Height < 0)
for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++)
{ {
short target_y; negative_height=1;
target_y = negative_height ? y_pos : context->Height-1-y_pos; header.Height = -header.Height;
}
if (Read_bytes(file,buffer,line_size))
for (x_pos=0,index=0; x_pos<context->Width; x_pos++,index+=3)
Set_pixel_24b(context, x_pos,target_y,buffer[index+2],buffer[index+1],buffer[index+0]);
else else
{
negative_height=0;
}
// Image 16/24/32 bits
if (header.Nb_bits == 16)
{
mask[0] = 0x00007C00;
mask[1] = 0x000003E0;
mask[2] = 0x0000001F;
}
else
{
mask[0] = 0x00FF0000;
mask[1] = 0x0000FF00;
mask[2] = 0x000000FF;
}
{
Pre_load(context, header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE,true_color);
if (File_error==0)
{
if (true_color)
{
if (header.Compression == 3) // BI_BITFIELDS
{
if (!Read_dword_le(file,&mask[0]) ||
!Read_dword_le(file,&mask[1]) ||
!Read_dword_le(file,&mask[2]))
File_error=2; File_error=2;
} }
break;
// 32bit bitmap
case 32:
line_size=context->Width*4;
buffer=(byte *)malloc(line_size);
for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++)
{
short target_y;
target_y = negative_height ? y_pos : context->Height-1-y_pos;
if (Read_bytes(file,buffer,line_size))
for (x_pos=0; x_pos<context->Width; x_pos++)
{
dword pixel=*(((dword *)buffer)+x_pos);
Set_pixel_24b(context, x_pos,target_y,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask));
} }
else else
{
Load_BMP_Palette(context, file, nb_colors, header.Size_2 == 12);
}
if (File_error==0)
{
if (fseek(file, header.Offset, SEEK_SET))
File_error=2; File_error=2;
}
break;
// 16bit bitmap
case 16:
line_size=(context->Width*2) + (context->Width&1)*2;
buffer=(byte *)malloc(line_size);
for (y_pos=0; (y_pos < context->Height && !File_error); y_pos++)
{
short target_y;
target_y = negative_height ? y_pos : context->Height-1-y_pos;
if (Read_bytes(file,buffer,line_size))
for (x_pos=0; x_pos<context->Width; x_pos++)
{
word pixel=*(((word *)buffer)+x_pos);
Set_pixel_24b(context, x_pos,target_y,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask));
}
else else
File_error=2; Load_BMP_Pixels(context, file, header.Compression, header.Nb_bits, negative_height, mask);
} }
break;
}
free(buffer);
buffer = NULL;
fclose(file);
} }
} }
} }
else else
{ {
fclose(file);
File_error=1; File_error=1;
} }
fclose(file);
} }
else else
File_error=1; File_error=1;