Я потратил несколько часов, пытаясь преобразовать монохромное растровое изображение, созданное FreeType, в массив пикселей, который использует 8 бит на пиксель (чтобы я мог использовать их в качестве альфа-значений для OpenGL). Я знаю, что могу просто взять обычное растровое изображение 8bpp и использовать его, но мне действительно нужна монохромная версия. А я уже пробовал метод пороговой обработки пикселей, но результат совсем не устраивает. Кажется, что если у вас есть версия со сглаживанием, вы просто не можете вернуться.
Фрагмент ниже — это то, что у меня есть сейчас, и он очень близок к тому, чтобы работать правильно, за исключением нескольких букв.
if (FT_Load_Glyph(face, glyphIndex, FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO))
throw exception();
if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO))
throw exception();
const Size bitmapSize = Size(
face->glyph->metrics.width / 64, face->glyph->metrics.height / 64
);
u8 *bitmapBits = face->glyph->bitmap.buffer;
u8 *bitmapBytes = new u8[bitmapSize.width * bitmapSize.height];
memset(bitmapBytes, 0, bitmapSize.width * bitmapSize.height);
int width = face->glyph->bitmap.width;
int height = face->glyph->bitmap.rows;
const u8 *src = bitmapBits;
for (int row = 0; row < height; ++row)
{
u8 *dst = &bitmapBytes[row * width];
for (int col = 0; col < width / 8; ++col)
{
u8 byte = src[col];
*dst++ = ((byte & (1 << 7)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 6)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 5)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 4)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 3)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 2)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 1)) != 0) ? 255: 0;
*dst++ = ((byte & (1 << 0)) != 0) ? 255: 0;
}
u8 trailingByte = src[width / 8];
int i = 7;
switch (width % 8)
{
case 7: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 6: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 5: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 4: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 3: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 2: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 1: *dst++ = ((trailingByte & (1 << (i--))) != 0) ? 255 : 0;
case 0: break;
}
src += face->glyph->bitmap.pitch;
}
Вот результат:
Я пытался выяснить, что общего у искаженных букв (может быть, это могло бы мне помочь), но я не знаю.
На самом деле, я не знаю, что не так с тем, как я это делаю. Но должно быть что-то, что я упускаю. Изменение шрифта не решает проблему (за исключением искажения букв, отличных от прежних).
Изменить: я заметил, что face->glyph->bitmap.width
и face->glyph->bitmap.rows
иногда возвращают несколько разные значения, чем face->glyph->metrics.width / 64
и face->glyph->metrics.height / 64
. Я пробовал их переключать, и рендеринг определенно стал лучше, но все еще есть некоторые символы (например, «t» и «g» в Arial и «X» и «0» в Microsoft Sans Serif), которые немного сдвинуты или искажены.
Это действительно странно, и я должен что-то упустить, потому что я не верю, что это ошибка. FreeType кажется слишком солидной и надежной библиотекой. Кроме того, загрузка шрифтов как немонохроматических работает отлично, так что это не проблема с кодом, который отображает строку.