Support transparency in ICO files with 256 colors or less

This commit is contained in:
Thomas Bernard 2018-01-18 00:43:36 +01:00
parent 2a04e363be
commit d0d0b64ecf

View File

@ -1460,7 +1460,12 @@ static void Load_BMP_Palette(T_IO_Context * context, FILE * file, unsigned int n
} }
} }
static void Load_BMP_Pixels(T_IO_Context * context, FILE * file, unsigned int compression, unsigned int nbbits, int top_down, const dword * mask) // rows are stored from the top to the bottom (standard for BMP is from bottom to the top)
#define LOAD_BMP_PIXEL_FLAG_TOP_DOWN 0x01
// We are decoding the AND-mask plane (transparency) of a .ICO file
#define LOAD_BMP_PIXEL_FLAG_TRANSP_PLANE 0x02
static void Load_BMP_Pixels(T_IO_Context * context, FILE * file, unsigned int compression, unsigned int nbbits, int flags, const dword * mask)
{ {
unsigned int row_size; unsigned int row_size;
unsigned int index; unsigned int index;
@ -1479,7 +1484,7 @@ static void Load_BMP_Pixels(T_IO_Context * context, FILE * file, unsigned int co
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 = top_down ? y_pos : context->Height-1-y_pos; target_y = (flags & LOAD_BMP_PIXEL_FLAG_TOP_DOWN) ? y_pos : context->Height-1-y_pos;
if (Read_bytes(file,buffer,row_size)) if (Read_bytes(file,buffer,row_size))
{ {
@ -1489,12 +1494,21 @@ static void Load_BMP_Pixels(T_IO_Context * context, FILE * file, unsigned int co
{ {
case 8 : case 8 :
value = buffer[x_pos]; value = buffer[x_pos];
Set_pixel(context, x_pos, target_y, value);
break; break;
case 4 : case 4 :
value = (x_pos & 1) ? (buffer[x_pos>>1] & 0xF) : (buffer[x_pos>>1] >> 4); value = (x_pos & 1) ? (buffer[x_pos>>1] & 0xF) : (buffer[x_pos>>1] >> 4);
Set_pixel(context, x_pos, target_y, value);
break; break;
case 1 : case 1 :
value = ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) ? 1 : 0; value = ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) ? 1 : 0;
if (flags & LOAD_BMP_PIXEL_FLAG_TRANSP_PLANE)
{
if (value) // transparent pixel !
Set_pixel(context, x_pos, target_y, context->Transparent_color);
}
else
Set_pixel(context, x_pos, target_y, value);
break; break;
case 24: case 24:
Set_pixel_24b(context, x_pos,target_y,buffer[x_pos*3+2],buffer[x_pos*3+1],buffer[x_pos*3+0]); Set_pixel_24b(context, x_pos,target_y,buffer[x_pos*3+2],buffer[x_pos*3+1],buffer[x_pos*3+0]);
@ -1514,8 +1528,6 @@ static void Load_BMP_Pixels(T_IO_Context * context, FILE * file, unsigned int co
default: default:
value = 0; value = 0;
} }
if (nbbits <= 8)
Set_pixel(context, x_pos, target_y, value);
} }
} }
else else
@ -1781,7 +1793,7 @@ void Load_BMP(T_IO_Context * context)
if (fseek(file, header.Offset, SEEK_SET)) if (fseek(file, header.Offset, SEEK_SET))
File_error=2; File_error=2;
else else
Load_BMP_Pixels(context, file, header.Compression, header.Nb_bits, negative_height, mask); Load_BMP_Pixels(context, file, header.Compression, header.Nb_bits, negative_height ? LOAD_BMP_PIXEL_FLAG_TOP_DOWN : 0, mask);
} }
} }
} }
@ -2083,12 +2095,22 @@ void Load_ICO(T_IO_Context * context)
&& Read_dword_le(file,&(bmpheader.Nb_Clr)) && Read_dword_le(file,&(bmpheader.Nb_Clr))
&& Read_dword_le(file,&(bmpheader.Clr_Imprt)) ) && Read_dword_le(file,&(bmpheader.Clr_Imprt)) )
{ {
short real_height;
word nb_colors = 0; word nb_colors = 0;
if (bmpheader.Nb_Clr != 0) if (bmpheader.Nb_Clr != 0)
nb_colors=bmpheader.Nb_Clr; nb_colors=bmpheader.Nb_Clr;
else else
nb_colors=1<<bmpheader.Nb_bits; nb_colors=1<<bmpheader.Nb_bits;
// bmpheader.Width != entry.width...
real_height = bmpheader.Height / 2;
if (bmpheader.Height < 0) real_height = - real_height;
// check that real_height == entry->height
if (real_height != entry->height)
{
Warning("Load_ICO() : real_height != entry->height");
}
// Image 16/24/32 bits // Image 16/24/32 bits
if (bmpheader.Nb_bits == 16) if (bmpheader.Nb_bits == 16)
{ {
@ -2102,7 +2124,7 @@ void Load_ICO(T_IO_Context * context)
mask[1] = 0x0000FF00; mask[1] = 0x0000FF00;
mask[2] = 0x000000FF; mask[2] = 0x000000FF;
} }
Pre_load(context, bmpheader.Width,bmpheader.Height/2,0/*file_size*/,FORMAT_ICO,PIXEL_SIMPLE,(bmpheader.Nb_bits > 8) || (nb_colors > 256)); Pre_load(context, bmpheader.Width,real_height,File_length_file(file),FORMAT_ICO,PIXEL_SIMPLE,(bmpheader.Nb_bits > 8) || (nb_colors > 256));
if (bmpheader.Nb_bits <= 8) if (bmpheader.Nb_bits <= 8)
Load_BMP_Palette(context, file, nb_colors, 0); Load_BMP_Palette(context, file, nb_colors, 0);
else else
@ -2117,7 +2139,15 @@ void Load_ICO(T_IO_Context * context)
} }
if (File_error == 0) if (File_error == 0)
{ {
Load_BMP_Pixels(context, file, bmpheader.Compression, bmpheader.Nb_bits, (bmpheader.Height < 0) ? 1 : 0, mask); Load_BMP_Pixels(context, file, bmpheader.Compression, bmpheader.Nb_bits, (bmpheader.Height < 0) ? LOAD_BMP_PIXEL_FLAG_TOP_DOWN : 0, mask);
// load transparency
// TODO : load transparency for True color images too
if (bmpheader.Nb_bits <= 8)
{
context->Transparent_color = 0xff; // TODO : pick an unused color if possible
context->Background_transparent = 1;
Load_BMP_Pixels(context, file, bmpheader.Compression, 1, (bmpheader.Height < 0) ? (LOAD_BMP_PIXEL_FLAG_TOP_DOWN|LOAD_BMP_PIXEL_FLAG_TRANSP_PLANE) : LOAD_BMP_PIXEL_FLAG_TRANSP_PLANE, mask);
}
} }
} }
} }