Sign in to follow this  

Distorted freetype fonts

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi!

I'm trying to load and display a character bitmap rendered by the freetype library.


FT_Library library;

if (FT_Init_FreeType(&library)) {

LogManager::GetInstance()->LogMessage("Could not initialize FreeType library.", LL_ERROR);
return 0;
}

FT_Face face;
unsigned int error;

error = FT_New_Face(library, "tests/font/arialbd.ttf", 0, &face);

if (error == FT_Err_Unknown_File_Format) {

LogManager::GetInstance()->LogMessage("Unknown file format.", LL_ERROR);
} else if (error) {
LogManager::GetInstance()->LogMessage("Could not load font file.", LL_ERROR);
}

error = FT_Set_Char_Size(face, 25 << 6, 25 << 6, 96, 96);


FT_Load_Glyph(face, FT_Get_Char_Index(face, 'A'), FT_LOAD_RENDER);
FT_Bitmap& bitmap = face->glyph->bitmap;

unsigned char* bitmapBuffer = new unsigned char[bitmap.width * bitmap.rows];

for (unsigned int i = 0; i < bitmap.rows; i++) {
for (unsigned int j = 0; j < bitmap.width; j++) {

bitmapBuffer[j + i * bitmap.width] = bitmap.buffer[j + i * bitmap.width];
}
}



The above code initializes the freetype library and loads a character in ('A' in this case).
After that, it gets the glyph's bitmap dimensions and allocates a buffer to store the glyph image.
Unfortunately, all I get is a distorted version of the character, as you can see from the following picture:


The weird thing is that for some other characters, it works just fine:


I really can't figure out what's wrong.

Thanks in advance!

Share this post


Link to post
Share on other sites
Looks like your rows are too tight for some characters. My bet is that for these characters the width is NOT a multiple of four and is rounded down to satisfy width % 4 == 0

I don't see it at one glance, I find freetype a little cumbersome in this respect, but what you must do is debug (write to a log) the character you're printing, width, height, pitch, ... all metrics. And see what is different for bad glyphs over good glyphs.

One thing to note, is that you should use pitch for row offsets from the destination (from FT).
bitmapBuffer[j + i * bitmap.width] = bitmap.buffer[j + i * bitmap.pitch];

Keep the other widths the same, it should be good like this.

EDIT: looking closer, it looks like your B is up-side-down!

Share this post


Link to post
Share on other sites
Could be the bitmap's width is different from its pitch?
bitmapBuffer[j + i * bitmap.width] = bitmap.buffer[j + i * bitmap.pitch];
Does that help?

EDIT: Beaten :(

EDIT2:
Quote:
Original post by Decrius
EDIT: looking closer, it looks like your B is up-side-down!

I think Freetype stores its bitmaps with the origin in the lower-left, so you need to reverse the row order to get things right-side-up... either that or some other bit of what he's doing acts that way... it's always so hard to keep straight which libraries keep their origin where once I already have "black box" code that just deals with it all for me, but it's upside down because of that I'd bet.

Share this post


Link to post
Share on other sites
Yes, the B is up-side-down, as Shinkage said, the problem is the way freetype stores bitmaps. Not really a problem indeed, just have to reverse the rows.

However, using pitch instead of width doesn't solve the issue. It seems that for some characters the buffer size doesn't match width * rows (or width * pitch). It's like freetype uses a fixed width/height for all glyphs and uses that one for all the others. I'm going to do some debug and update as soon as possible.

Share this post


Link to post
Share on other sites
Ok, wrote a little program to check bitmaps that don't look right, here the results:


A - WRONG
bitmap width : 37
bitmap rows : 38
bitmap pitch : 37

B - CORRECT
bitmap width : 32
bitmap rows : 38
bitmap pitch : 32

C - WRONG
bitmap width : 33
bitmap rows : 39
bitmap pitch : 33

D - CORRECT
bitmap width : 32
bitmap rows : 38
bitmap pitch : 32

E - CORRECT
bitmap width : 28
bitmap rows : 38
bitmap pitch : 28

F - WRONG
bitmap width : 25
bitmap rows : 38
bitmap pitch : 25

G - CORRECT
bitmap width : 36
bitmap rows : 40
bitmap pitch : 36

H - WRONG
bitmap width : 30
bitmap rows : 38
bitmap pitch : 30

I - WRONG
bitmap width : 7
bitmap rows : 38
bitmap pitch : 7

J - CORRECT
bitmap width : 24
bitmap rows : 39
bitmap pitch : 24

K - WRONG
bitmap width : 34
bitmap rows : 38
bitmap pitch : 34

L - WRONG
bitmap width : 26
bitmap rows : 38
bitmap pitch : 26

M - WRONG
bitmap width : 35
bitmap rows : 38
bitmap pitch : 35

N - WRONG
bitmap width : 30
bitmap rows : 38
bitmap pitch : 30

O - WRONG
bitmap width : 37
bitmap rows : 40
bitmap pitch : 37

P - WRONG
bitmap width : 29
bitmap rows : 38
bitmap pitch : 29

Q - WRONG
bitmap width : 38
bitmap rows : 43
bitmap pitch : 38

R - WRONG
bitmap width : 34
bitmap rows : 38
bitmap pitch : 34

S - WRONG
bitmap width : 30
bitmap rows : 40
bitmap pitch : 30

T - WRONG
bitmap width : 29
bitmap rows : 38
bitmap pitch : 29

U - WRONG
bitmap width : 30
bitmap rows : 39
bitmap pitch : 30

V - WRONG
bitmap width : 35
bitmap rows : 38
bitmap pitch : 35

W - WRONG
bitmap width : 49
bitmap rows : 38
bitmap pitch : 49

X - WRONG
bitmap width : 35
bitmap rows : 38
bitmap pitch : 35

Y - WRONG
bitmap width : 35
bitmap rows : 38
bitmap pitch : 35

Z - WRONG
bitmap width : 30
bitmap rows : 38
bitmap pitch : 30



So I think you are right Decrius, bitmaps' widths should be aligned to the nearest largest multiple of 4, shouldn't they?

Share this post


Link to post
Share on other sites
Quote:
Original post by Taylor001
However, using pitch instead of width doesn't solve the issue. It seems that for some characters the buffer size doesn't match width * rows (or width * pitch). It's like freetype uses a fixed width/height for all glyphs and uses that one for all the others. I'm going to do some debug and update as soon as possible.


Are you sure that you're not accidentally using the pitch when writing into the memory buffer you allocated yourself?

Besides the pitch thing I can't see what should be wrong with your code, although I don't understand why your glyphs are coming out upside down - in my freetype code I certainly don't flip them and it works fine.

Can you post how your code looks after you changed the pitch thing?

Have you tried printing your glyphs to stdout with printf() to verify that the problem isn't later in your rendering pipeline?

Share this post


Link to post
Share on other sites
Quote:
Original post by rneckelmann
Quote:
Original post by Taylor001
However, using pitch instead of width doesn't solve the issue. It seems that for some characters the buffer size doesn't match width * rows (or width * pitch). It's like freetype uses a fixed width/height for all glyphs and uses that one for all the others. I'm going to do some debug and update as soon as possible.


Are you sure that you're not accidentally using the pitch when writing into the memory buffer you allocated yourself?

Besides the pitch thing I can't see what should be wrong with your code, although I don't understand why your glyphs are coming out upside down - in my freetype code I certainly don't flip them and it works fine.

Can you post how your code looks after you changed the pitch thing?

Have you tried printing your glyphs to stdout with printf() to verify that the problem isn't later in your rendering pipeline?


The new pitched code looks like this:


for (unsigned int i = 0; i &lt; bitmap.rows; i++) {
for (unsigned int j = 0; j &lt; bitmap.width; j++) {

bitmapBuffer[j + i * bitmap.width] = bitmap.buffer[j + i * bitmap.pitch];
}
}



Bitmap rendering is done through a call to glDrawPixels(bitmap.width, bitmap.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, bitmapBuffer);

Share this post


Link to post
Share on other sites
Quote:
Bitmap rendering is done through a call to glDrawPixels(bitmap.width, bitmap.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, bitmapBuffer);


Ah, okay, that atleast explains the flipping :P.

I looked at my old code again and saw that I'm using FT_Set_Pixel_Sizes() to specify the size of my font in screen pixels in contrary to your FT_Set_Char_Size() which works in device units.

For the individual glyphs I calculate the width and height in pixels:

int nWidth = SomeFace->glyph->metrics.width / 64;
int nHeight = SomeFace->glyph->metrics.height / 64;


I guess you can fix your problem by doing something similar, although I have no clue why FT_Set_Char_Size() isn't producing the same results. (It's probably related to your glyph dimensions ending up as non-integer for some specific glyphs...)

[Edited by - rneckelmann on August 27, 2010 6:35:27 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Taylor001
Tried switching to FT_Set_Pixel_Sizes but result is the same.
bitmap.rows/width and metrics.width/height >> 6 produce the same results, so, nothing changes. :\


Very strange. Someone above mentioned something about multiple of 4. Tried snapping your glyph sizes to that?

Otherwise try to grab one of the tutorials from freetype.org and slowly change it into what you got now - and check when it stops to work :P

Share this post


Link to post
Share on other sites
For win32 bitmaps, each scanline is stored as a multiple of 4(bytes). Assuming we're talking about a 24bpp bitmap, it looks like your calculating each pixel wrong. Try something like this.

BMPPixel GetBMPPixel( BMP* Bitmap, int x, int y )
{
DWORD BytesPerLine = Bitmap->Width * 3;

DWORD PaddingPerLine = 0;

if( BytesPerLine % 4 != 0 )
{
PaddingPerLine = 4 - (BytesPerLine % 4);
}

return *(BMPPixel*)&Bitmap->PixelData[(x * 3) + y * (BytesPerLine + PaddingPerLine)];
}




It also looks like your buffer may be to small. Again assuming 24bpp bitmaps, it should be this size

unsigned char* bitmapBuffer = new unsigned char[bitmap.width * bitmap.rows * 3];





If that is the case, than this might even work.

bitmapBuffer[(j * 3) + i * bitmap.width] = bitmap.buffer[(j * 3) + i * bitmap.width];




The reason your code my work for some glyphs may be due to the glyphs already being a multiple of 4. So there is no need for padding. The diagonal-looking figure you have practically screams some sort of offset issue.

Share this post


Link to post
Share on other sites
Quote:
Original post by fitfool
It also looks like your buffer may be to small. Again assuming 24bpp bitmaps, it should be this size


There are no colors. The stuff that comes out of freetype2 is grayscale and the OpenGL command he posted earlier to draw the glyph was also grayscale.

Share this post


Link to post
Share on other sites
Quote:
Original post by fitfool
It also looks like your buffer may be to small. Again assuming 24bpp bitmaps, it should be this size
*** Source Snippet Removed ***


If that is the case, than this might even work.
*** Source Snippet Removed ***

The reason your code my work for some glyphs may be due to the glyphs already being a multiple of 4. So there is no need for padding. The diagonal-looking figure you have practically screams some sort of offset issue.


This is true for sub-pixel rendering.

If you look close at the debug results, all widths with a multiple of 4 display correctly. Try to increase the width so it meets a multiple of 4, someone above posted the code I think.

Share this post


Link to post
Share on other sites
Ok!

Indeed the issue was padding related but the problem itself is due to the way glDrawPixels interprets the bitmap's rows. "By default, these pixels are taken from adjacent memory locations, except that after all width pixels are read, the read pointer is advanced to the next four-byte boundary.". A call to glPixelStorei(GL_UNPACK_ALIGNMENT, 1) solves it all.

Thanks for the help! ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by Taylor001
Ok!

Indeed the issue was padding related but the problem itself is due to the way glDrawPixels interprets the bitmap's rows. "By default, these pixels are taken from adjacent memory locations, except that after all width pixels are read, the read pointer is advanced to the next four-byte boundary.". A call to glPixelStorei(GL_UNPACK_ALIGNMENT, 1) solves it all.

Thanks for the help! ;)


Man that one always pops up when I'm not expecting it.

Share this post


Link to post
Share on other sites
[quote name='Taylor001' timestamp='1283005468' post='4698214']
A call to glPixelStorei(GL_UNPACK_ALIGNMENT, 1) solves it all.

Thanks for the help! ;)
[/quote]

Thanks, great help.


In my case i had to use:
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this