Hi there.

I see that SDL does a very good job converting and using different

depths but I wanted to learn to do that myself and the way SDL does

isn’t very clear to me.

Actually, I understand how, for instance, I have a 24bpp RGB data and

want to make a 16bpp (565) but what about the other way around? How can

I calculate by hand, if I have a 16bpp data and want a 24 bpp which is

visually equivallent?

I tought about something like:

RGB32 = ((Red16 & 0xf800) << 8) | ((Green16 & 0x07e0) << 5) | ((Blue16 &

0x001f) << 3)

This kinda works but some colors are not quite correct.

Any ideas?

Thanks.

Adilson.

Adilson Oliveira wrote:

How can I calculate by hand, if I have a 16bpp data and want a 24 bpp

which is visually equivallent?

I tought about something like:

RGB32 = ((Red16 & 0xf800) << 8) | ((Green16 & 0x07e0) << 5) | ((Blue16 &

0x001f) << 3)

This kinda works but some colors are not quite correct.

E.g. for the blue component, you have to convert from the range 0…31 to

the range 0…255. That’s done by multiplying by 255/31 = 8.226, not by

multiplying by 8 (i.e. shifting by 3 bits). The same for the other

components, except that it’s 0…63 for green.

Just try inserting white (0b1111111111111111) into your formula: you

will get 0b111110001111110011111000, while what you should get is

0b111111111111111111111111.

-Christian

Christian Walther wrote:

Adilson Oliveira wrote:

How can I calculate by hand, if I have a 16bpp data and want a 24 bpp

which is visually equivallent?

I tought about something like:

RGB32 = ((Red16 & 0xf800) << 8) | ((Green16 & 0x07e0) << 5) | ((Blue16

& 0x001f) << 3)

This kinda works but some colors are not quite correct.

E.g. for the blue component, you have to convert from the range 0…31 to

the range 0…255. That’s done by multiplying by 255/31 = 8.226, not by

multiplying by 8 (i.e. shifting by 3 bits). The same for the other

components, except that it’s 0…63 for green.

Just try inserting white (0b1111111111111111) into your formula: you

will get 0b111110001111110011111000, while what you should get is

0b111111111111111111111111.

You’re absolutely right. Now you see what causes lot’s of problems and

lack of sleep

Now I’ll think in a more efficient way to make this without having to

rely on real number calculations. Perhaps, I should have some sleep first

Thanks.

Adilson.

Hi,

Selon Christian Walther :

Adilson Oliveira wrote:

How can I calculate by hand, if I have a 16bpp data and want a 24 bpp

which is visually equivallent?

I tought about something like:

RGB32 = ((Red16 & 0xf800) << 8) | ((Green16 & 0x07e0) << 5) | ((Blue16 &

0x001f) << 3)

This kinda works but some colors are not quite correct.

E.g. for the blue component, you have to convert from the range 0…31 to

the range 0…255. That’s done by multiplying by 255/31 = 8.226, not by

multiplying by 8 (i.e. shifting by 3 bits). The same for the other

components, except that it’s 0…63 for green.

Just try inserting white (0b1111111111111111) into your formula: you

will get 0b111110001111110011111000, while what you should get is

0b111111111111111111111111.

You can achieve this using only integers :

R5 = RGB16 & 0xF800;

G6 = RGB16 & 0x07E0;

B5 = RGB16 & 0x001F;

R8 = (R5 >> 8) | (R5 >> 13);

G8 = (G6 >> 3) | (G6 >> 9);

B8 = (B5 << 3) | (B5 >> 2);

RGB24 = (R8 << 16) | (G8 << 8) | B8;

This way you get for each possible value of B5 :

0b00000 : 0b00000000

0b00001 : 0b00001000

0b00010 : 0b00010000

0b00011 : 0b00011000

0b00100 : 0b00100001

0b00101 : 0b00101001

0b00110 : 0b00110001

0b00111 : 0b00111001

0b01000 : 0b01000010

0b01001 : 0b01001010

0b01010 : 0b01010010

0b01011 : 0b01011010

0b01100 : 0b01100011

0b01101 : 0b01101011

0b01110 : 0b01110011

0b01111 : 0b01111011

0b10000 : 0b10000100

0b10001 : 0b10001100

0b10010 : 0b10010100

0b10011 : 0b10011100

0b10100 : 0b10100101

0b10101 : 0b10101101

0b10110 : 0b10110101

0b10111 : 0b10111101

0b11000 : 0b11000110

0b11001 : 0b11001110

0b11010 : 0b11010110

0b11011 : 0b11011110

0b11100 : 0b11100111

0b11101 : 0b11101111

0b11110 : 0b11110111

0b11111 : 0b11111111

As you can see, it’s just copying the 3 most significant bits of B5 in the 3

least significant bits of B8.

Regards,

Xavier

Xavier Joubert wrote:

E.g. for the blue component, you have to convert from the range 0…31 to

the range 0…255. That’s done by multiplying by 255/31 = 8.226, not by

multiplying by 8 (i.e. shifting by 3 bits). The same for the other

components, except that it’s 0…63 for green.

Just try inserting white (0b1111111111111111) into your formula: you

will get 0b111110001111110011111000, while what you should get is

0b111111111111111111111111.

You can achieve this using only integers :

R5 = RGB16 & 0xF800;

G6 = RGB16 & 0x07E0;

B5 = RGB16 & 0x001F;

R8 = (R5 >> 8) | (R5 >> 13);

G8 = (G6 >> 3) | (G6 >> 9);

B8 = (B5 << 3) | (B5 >> 2);

RGB24 = (R8 << 16) | (G8 << 8) | B8;

This way you get for each possible value of B5 :

0b00000 : 0b00000000

0b00001 : 0b00001000

…

0b11110 : 0b11110111

0b11111 : 0b11111111

As you can see, it’s just copying the 3 most significant bits of B5 in the 3

least significant bits of B8.

Clever idea. It doesn’t always round to the nearest 8-bit value though -

it’s off by 1 in 4 of the 32 cases. But the more efficient

implementation may well be worth it.

I’d have done it using integer multiplication and division: B8 = (B5*255

Xavier Joubert wrote:

Hi,

Selon Christian Walther :

Adilson Oliveira wrote:

How can I calculate by hand, if I have a 16bpp data and want a 24 bpp

which is visually equivallent?

I tought about something like:

RGB32 = ((Red16 & 0xf800) << 8) | ((Green16 & 0x07e0) << 5) | ((Blue16 &

0x001f) << 3)

This kinda works but some colors are not quite correct.

E.g. for the blue component, you have to convert from the range 0…31 to

the range 0…255. That’s done by multiplying by 255/31 = 8.226, not by

multiplying by 8 (i.e. shifting by 3 bits). The same for the other

components, except that it’s 0…63 for green.

Just try inserting white (0b1111111111111111) into your formula: you

will get 0b111110001111110011111000, while what you should get is

0b111111111111111111111111.

You can achieve this using only integers :

R5 = RGB16 & 0xF800;

G6 = RGB16 & 0x07E0;

B5 = RGB16 & 0x001F;

R8 = (R5 >> 8) | (R5 >> 13);

G8 = (G6 >> 3) | (G6 >> 9);

B8 = (B5 << 3) | (B5 >> 2);

RGB24 = (R8 << 16) | (G8 << 8) | B8;

Thanks for the tip.

Actually I already cooked up something quite similar and packed into one

line of code only, like this:

*out = ((((*data16 >> 8) & 0xf8) | ((*data16 >> 13) & 0x07)) << 16) |

((((*data16 >> 3) & 0xfc) | ((*data16 >> 9) & 0x03)) << 8) |

(((*data16 << 3) & 0xf8) | ((*data16 >> 2) & 0x07));

[]s

Adilson.

Hi,

Selon Christian Walther :

Clever idea. It doesn’t always round to the nearest 8-bit value though -

it’s off by 1 in 4 of the 32 cases. But the more efficient

implementation may well be worth it.

Not on a modern CPU, where dividing has almost the same cost as shifting. The

bottleneck would be the memory on such system.

But this may make a difference where dividing is very expensive (old CPU,

embedded system…).

Regards,

Xavier