# freetype FT_PIXEL_MODE_LCD to rgba

This topic is 1651 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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

Edited by jeff8j

##### Share on other sites

Is one of your loop ending conditions a typo?


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


##### Share on other sites

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.

Edited by Brother Bob

##### Share on other sites

@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

##### Share on other sites

@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.

##### Share on other sites

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

##### Share on other sites

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 ) 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.

Edited by Brother Bob

##### Share on other sites

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?

Edited by jeff8j

##### Share on other sites

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?

##### Share on other sites

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.

##### Share on other sites

Darn I figured that since it didnt have rgb it couldnt be antialiased but I guess it can just not on subpixel level like you say.

Do I need to get rid of antialiasing all together?

I added a solid rgb and just changed the alhpa like this and it didnt look much different

data.append(3, (unsigned char)255);
data.append(1, (unsigned char)bitmap.buffer[(y*width) + x] );


Im not quite sure what you mean when blending to me blending and alpha testing sound the same and are you talking about when I make the images of the characters into one image?

##### Share on other sites

Alpha blending and alpha testing are not the same thing. Alpha testing is a binary test that, using on some threshold of the alpha value, either fully draws a pixel or fully rejects it for further processing. Alpha blending is used when you have partially transparent pixels that has to blend gradually with the background. Take for example an edge pixel with a normalized alpha value of 0.25 (255*0.25=64 in 8-bit integer values); it means that is is 25% opaque and has to blend 25% with its own solid color and 75% with the background.

Edited by Brother Bob

##### Share on other sites

Ah I see what you mean I saved just one character to a png straight from freetype and it looks great so something is wrong with my blending of the images. I will get on that and figure out whats going on! The T in the images looks to have the top part better than in the complete image I wonder if it has something to do with the merging to. Thanks for your help!

##### Share on other sites

Either you're cutting off the last top, or the top line just happens to be sharp. Fonts designed for rasterization, or if the library has a decent font hinting method, typically places the stems of the glyphs on pixel boundaries to eliminate the effect of antialiasing since there are no partial coverages in those cases. This is often desired, since antialiasing is meant to reduce the aliasing effects and the design/hinting strives to eliminate the aliasing in the first place. But I would double check that your code actually does copy all rows, if something missing it is probably the last row of the T, and one-off errors are not uncommon.

Edited by Brother Bob

##### Share on other sites

I made a little progress on getting them lined up properly and showing the whole characters im not sure whats wrong with the T but everything else looks ok aligned wise but im having an issue with my blending. Can you help get my blending sorted out please?

my varaibles are unsigned chars r,g,b,a,destr,destg,destb,desta

the rgba contain the new/top image that will be placed on the destrgba canvas

right not just to see what im doing im using

r = r * (a / 255);
g = g * (a / 255);
b = b * (a / 255);
a = 255;


My original code was

r = (r * a) + (destr * (255 - desta));
g = (g * a) + (destg * (255 - desta));
b = (b * a) + (destb * (255 - desta));
a = 255;



Neither of these seem to be correct and I just cant wrap my head on what to do can you help please?

##### Share on other sites

Your second code is almost correct, but has to be scaled. It is correct for a normalized alpha channel, but since your alpha is scaled by 255, you also have to divide the result by 255 after multiplication to scale the product back to its actual range.

r = ((r * a) + (destr * (255 - desta))) / 255;
g = ((g * a) + (destg * (255 - desta))) / 255;
b = ((b * a) + (destb * (255 - desta))) / 255;
a = 255;


##### Share on other sites

Hmm I added that but it looks pretty much the same it must be off somewhere before the merging ill have to find where its going bad.

##### Share on other sites

Found the issue with the T I had it going x for height not y im really surprised the rest looked ok lol

##### Share on other sites

Freetype will either give you a very nicely anti-aliased 8-bit glyph bitmap or a rather rough monochrome bitmap.

When I was playing around with Freetype, I set the alpha channel of my bitmap to the value of the corresponding pixel in the glyph bitmap. I then set the RGB components of my bitmap to whatever color I wanted and used the resulting bitmap as a texture with blending enabled. The best thing to do with a Freetype bitmap, 8-bit or 1-bit, is to use it as the alpha channel of your bitmap.

##### Share on other sites

@MarkS I see but I think this is already covered and I know the output of the freetype is better than the string im getting as the characters are better

Just for show I changed the first character from T to lower case f because you can tell the alpha layer easily on it I attached the character and the string the character from freetype looks great the string doesnt and all the alpha data is the same so its definitely something in the merging that is causing issues.

##### Share on other sites

Hey if I use white it doesnt look half bad

All I did was change

data.append(3, (unsigned char)0);
data.append(1, (unsigned char)bitmap.buffer[(y*width) + x] );


to

data.append(3, (unsigned char)255);
data.append(1, (unsigned char)bitmap.buffer[(y*width) + x] );


Something doesnt seem right is that a bad way to change the text color?

it still doesnt look exact though as it has some black behind it that doesnt really look like a shadow is it just me?

Edited by jeff8j

##### Share on other sites

I had that issue as well. I was using shaders to do the blending and I got the blending wrong in the shader.

##### Share on other sites

What was your issue do you see something wrong with the way im blending?

##### Share on other sites

I think I got the problem but I dont have the solution.

I believe the problem is because the merge is setting the alpha to 255 and my original image is all zeros so its black with 100% transparency but it seems like its processing on the black and then using a new transparency of 255 so its not keeping a transparency level im not sure what to do on the src and dest alpha to get a new alpha value can someone help with that please?

##### Share on other sites

Can you post some more relevant code to show what you're actually doing and where everything is happening?