Converting a 24-bit image down to 8 bits

I’ve got an 8-bit BMP that SDL is loading as 24 bits for whatever reason. I try to save it as a PNG, but the PNG encoder chokes on the 24-bit depth. Since the data in here can be represented in just 8 BPP anyway, what’s the best way to convert the 24-bit SDL_Surface to an 8-bit SDL_Surface so I can save it?? I know I’ve gotta call SDL_ConvertSurface, but how do I get the right pixel format to pass in?

Mason

Mason,

How do you load the surface?. Do you optimize according to the screen format?
Which also leads to how are you setting up your screen?
I think your approaching the problem from the wrong direction, the key is what
your screen depth is set to. What ever it is your final image format needs to
match.________________________________
From: masonwheeler@yahoo.com (Mason Wheeler)
To: sdl
Sent: Tue, June 14, 2011 4:44:11 PM
Subject: [SDL] Converting a 24-bit image down to 8 bits

I’ve got an 8-bit BMP that SDL is loading as 24 bits for whatever reason. I try
to save it as a PNG, but the PNG encoder chokes on the 24-bit depth. Since the
data in here can be represented in just 8 BPP anyway, what’s the best way to
convert the 24-bit SDL_Surface to an 8-bit SDL_Surface so I can save it? I know
I’ve gotta call SDL_ConvertSurface, but how do I get the right pixel format to
pass in?

Mason

That doesn’t help.? I have no “screen”.? This is all happening purely in-memory; I’m just using SDL for format conversion.________________________________
From: pickle136@sbcglobal.net (Scott Smith)
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

Ah ok, you could try this then set the screen to run in 8 bpp mode and then pass the screen’s SDL_PixelFormat to the SDL_ConvertSurface. Then try to save it to file.


From: @Mason_Wheeler (Mason Wheeler)
To: Scott Smith
Sent: Tue, June 14, 2011 5:11:00 PM
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

I’m loading the surface with IMG_Load_RW, and I’m not trying to convert to any screen format because I’m trying to display this. I’m trying to convert and save to a 8-bit paletted PNG image on disc.? Screen format is 100% irrelevant here.


From: pickle136@sbcglobal.net (Scott Smith)
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

Mason,

How do you load the surface?. Do you optimize according to the screen format? Which also leads to how are you setting up your screen?
I think your approaching the problem from the wrong direction, the key is what your screen depth is set to. What ever it is your final image format needs to match.


From: @Mason_Wheeler (Mason Wheeler)
To: sdl
Sent: Tue, June 14, 2011 4:44:11 PM
Subject: [SDL] Converting a 24-bit image down to 8 bits

I’ve got an 8-bit BMP that SDL is loading as 24 bits for whatever reason. I try to save it as a PNG, but the PNG encoder chokes on the 24-bit depth. Since the data in here can be represented in just 8 BPP anyway, what’s the best way to convert the 24-bit SDL_Surface to an 8-bit SDL_Surface so I can save it?? I know I’ve gotta call SDL_ConvertSurface, but how do I get the right pixel format to pass in?

Mason

I just mentioned it cause it would be a easier to open a screen at 8 bpp and
rely on it to enter the pixel format information for you even if you never
blitted anything to screen. You could at least do it one time to get an idea
what the pixel format might need to look like.
What is your pixel format structure look like now?________________________________
From: masonwheeler@yahoo.com (Mason Wheeler)
To: sdl
Sent: Tue, June 14, 2011 5:34:07 PM
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

That doesn’t help. I have no “screen”. This is all happening purely in-memory;
I’m just using SDL for format conversion.


From: @Scott_Smith (Scott Smith)
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

Ah ok, you could try this then set the screen to run in 8 bpp mode and then pass
the screen’s SDL_PixelFormat to the SDL_ConvertSurface. Then try to save it to
file.


From: masonwheeler@yahoo.com (Mason Wheeler)
To: Scott Smith <@Scott_Smith>
Sent: Tue, June 14, 2011 5:11:00 PM
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

I’m loading the surface with IMG_Load_RW, and I’m not trying to convert to any
screen format because I’m trying to display this. I’m trying to convert and save
to a 8-bit paletted PNG image on disc. Screen format is 100% irrelevant here.


From: @Scott_Smith (Scott Smith)
Subject: Re: [SDL] Converting a 24-bit image down to 8 bits

Mason,

How do you load the surface?. Do you optimize according to the screen format?
Which also leads to how are you setting up your screen?
I think your approaching the problem from the wrong direction, the key is what
your screen depth is set to. What ever it is your final image format needs to
match.


From: masonwheeler@yahoo.com (Mason Wheeler)
To: sdl
Sent: Tue, June 14, 2011 4:44:11 PM
Subject: [SDL] Converting a 24-bit image down to 8 bits

I’ve got an 8-bit BMP that SDL is loading as 24 bits for whatever reason. I try
to save it as a PNG, but the PNG encoder chokes on the 24-bit depth. Since the
data in here can be represented in just 8 BPP anyway, what’s the best way to
convert the 24-bit SDL_Surface to an 8-bit SDL_Surface so I can save it? I know
I’ve gotta call SDL_ConvertSurface, but how do I get the right pixel format to
pass in?

Mason

I’ve got an 8-bit BMP that SDL is loading as 24 bits for whatever
reason. I try to save it as a PNG, but the PNG encoder chokes on the
24-bit depth. Since the data in here can be represented in just 8 BPP
anyway, what’s the best way to convert the 24-bit SDL_Surface to an
8-bit SDL_Surface so I can save it? I know I’ve gotta call
SDL_ConvertSurface, but how do I get the right pixel format to pass in?

Are you loading the BMP through SDL, or SDL_image? Both should be able
to give you an 8-bit, paletted surface.

Is it possible you’re using SDL_image on Mac OS X? Because that tries to
use Apple’s decoders by default, and those don’t play around with palettes.

If you have to have 24-bit data, and you have to convert it to 8-bit,
you probably don’t want SDL_ConvertSurface()…it sort of assumes you
have two existing surfaces so you’ll have the SDL_PixelFormat you want
available. It’s really meant to be used for “I just loaded this .bmp
file to a surface, now I want it in the same format as the screen
surface I got from SDL_SetVideoMode() so I don’t have to convert it
every time I blit.”

Fortunately, you can do the same thing as SDL_ConvertSurface() yourself,
without all the work it does for corner cases like colorkeys.

I’d try something like this:

SDL_Surface *surf24;
SDL_Surface *surf8;

surf24 = WhereverYouGotThe24BitSurface();
surf8 = SDL_CreateRGBSurface(SDL_SWSURFACE, surf24->w, surf24->h, 8, 0,
0, 0, 0);

// Create a palette here for however you want those 8 bits mapped.
// Let’s say you want this to be a gradient from black to white.
SDL_Color palette[256];
for (int i = 0; i < 256; i++)
{
palette[i].r = i;
palette[i].g = i;
palette[i].b = i;
palette[i].unused = 0;
}
SDL_SetPalette(surf8, SDL_LOGPAL, palette, 0, 256);

// Now blit from the 24-bit surface to the 8-bit one. SDL will use the
// palette to map between the colors as closely as possible.
SDL_BlitSurface(surf24, NULL, surf8, NULL);

// You’re done with the 24-bit surface now. Free it if you own it.
SDL_FreeSurface(surf24);

// Use the 8-bit one as you see fit. Don’t forget to SDL_FreeSurface()
// it afterwards!

–ryan.

1 Like