freetype FT_PIXEL_MODE_LCD to rgba

Started by
41 comments, last by Brother Bob 10 years, 8 months ago

Im using freetype for my game and getting the characters in FT_PIXEL_MODE_LCD type I then convert this to rgba to be easily put on top of other things and it works but im doing something wrong obviously to do with the alpha.

Heres my c++ code its already got the FT_Bitmap named bitmap


std::string data;
data.reserve(4 * width * height);
for( int y=0; y<height; y++ ){
    for( int x=0; x<width; x++){
        int pos = (y*pitch) + (x*3);
 
        if( (unsigned char)bitmap.buffer[pos] == 0 && (unsigned char)bitmap.buffer[pos+1] == 0 && (unsigned char)bitmap.buffer[pos+2] == 0 ){
            data.append(4, (unsigned char)0);
        } else {
            data.append(1, 255 - (unsigned char)bitmap.buffer[pos] );
            data.append(1, 255 - (unsigned char)bitmap.buffer[pos+1] );
            data.append(1, 255 - (unsigned char)bitmap.buffer[pos+2] );
            //alpha
            data.append(1, (unsigned char)255);
        }
    }
}

I do the 255 - the rgb chars to convert the data from white text on black background to black text on white background

Anyways the result is attached can someone help? Thanks

Advertisement

Is one of your loop ending conditions a typo?



for( int y=0; y<height; y++ ){
    for( int x=0; x<img->width; x++){

You have an antialiased font but a binary alpha, and the backgrounds color the glyphs are blended against (white) does not match the background outside the glyphs (blue) Therefore you get a gradual transition from the glyph foreground color to the glyph background color near the edge of the glyphs, and then a abrupt transition from the glyph background to the text background.

Take a paint program and replace all pure blue pixels with pure white and you will see a nice antialiased text. You will also noticed that some glyphs are cut in height. Looks like you're rendering all glyphs with the same height which happens to be the height of lower-case letters which cases the upper-case letters and some tall letters such as t and f to be cut at the top.

@Cosmic314 Nice catch but not really an issue because the img is the variable its stored in after the conversion and the image->width is already set to width

@Brother Bob I understand the white works thats why I changed it to blue I added the binary alpha because I cannot figure out a way to get a alpha. I dont want to change the background color to simply blue because the blue is just an example and it will eventually have things moving behind it and different images behind it so I need the alhpa.

So what are my options? Turn antialiasing off and use a simpler font? is there no way to get the alpha channel with the antialiasing? Thanks

@Brother Bob oh and thanks for clearing up the top being cut off I somehow managed to get it that far it was way worse lol Ill try to get the height working better to get the whole letters.

@Cosmic314 I changed it to just width for the sake of clarity! Thanks

I believe alpha and sub-pixel rendering don't play very well together. The value you get from FreeType is basically how much the glyph covers a sub-pixel (the individual colors are actually individual "greyscale" pixels with different colors, if that makes sense smile.png ) and each of those sub-pixels need to be blended individually for perfect result. You basically need an alpha channel for each color, since the coverages of each sub-pixel is different within a single whole RGB triplet pixel.

It is the part where you do the 255-{r,g,b} where the individual blending has to be done. I can't think of a nice work-around. I would advice to either have a fixed background color, or use greyscale font only where the pixel value is the alpha channel.

Ok now im using ft_render_mode_normal which is giving me a FT_PIXEL_MODE_GRAY pixel mode type

It should now not have antialiasing right?

Heres my code for the gray


std::string data;
data.reserve(4 * width * height);
for( int y=0; y<height; y++ ){
    for( int x=0; x<width; x++){
        data.append(4, (unsigned char)bitmap.buffer[(y*width) + x] );
    }
}

And my results doesnt look to good lol I still must be missing something with the alpha channel?

Not too concerned right now but for a future reference do most bigger games use subpixel fonts or do they do rely on the post processing anti aliasing?

Greyscale is still antialiased, just not on a sub-pixel level. What you want to do though is not replicate the greyscale level across all four color channels, because that effectively adds blended pixel values to the buffer and then blending blends them again. What you get is more or less blending with the square of the alpha channel. You want to instead add a solid color across the entire image, but vary only the alpha channel.

However, I suspect that the error in your image may be due to incorrect blending. Looks like you're not using blending at all, but alpha testing.

This topic is closed to new replies.

Advertisement