从FreeType位图创建Direct2D位图遇渲染异常,求正确实现方法
问题分析与解决方案
核心问题1:Direct2D Bitmap尺寸参数错误
创建D2D Bitmap时,你错误地将高度参数传为FTBitmap.pitch(每行字节数),正确高度应该是FTBitmap.rows(像素行数)。这个错误会导致D2D解析位图数据时出现拉伸、错乱的异常渲染结果。
核心问题2:像素格式不匹配
FreeType用FT_RENDER_MODE_NORMAL渲染出的是单通道8位灰度图(像素值代表alpha覆盖度,0为完全透明,255为完全不透明),但你直接传给了要求四通道的DXGI_FORMAT_B8G8R8A8_UNORM格式,D2D无法正确解析单通道数据。
次要问题:Bitmap数据打印循环索引错误
当前打印循环的索引逻辑错误,正确的像素地址应为j * Face->glyph->bitmap.pitch + i,而非i + j,原逻辑会导致打印的数据完全混乱。
修正后的代码示例
FT_Error Error = FT_Init_FreeType(&Library); assert(!Error); FT_Face Face; Error = FT_New_Face(Library, "Roboto.ttf", 0, &Face); assert(!Error); // 设置字体大小:16pt,96DPI Error = FT_Set_Char_Size(Face, 0, 16 * 64, 96, 96); assert(!Error); std::cout << "Loading Font " << Face->family_name << "\n\tNum Glyphs: " << Face->num_glyphs << std::endl; uint32_t Index = FT_Get_Char_Index(Face, 'L'); std::cout << "\tCharacter 'L' is at index " << Index << "\n"; Error = FT_Load_Glyph(Face, Index, FT_LOAD_DEFAULT); assert(!Error); // 渲染为8位alpha灰度图 Error = FT_Render_Glyph(Face->glyph, FT_RENDER_MODE_NORMAL); assert(!Error); // 修正后的Bitmap数据打印逻辑 FT_Bitmap& bitmap = Face->glyph->bitmap; for (int j = 0; j < bitmap.rows; j++) { for (int i = 0; i < bitmap.width; i++) { uint8_t pixel = bitmap.buffer[j * bitmap.pitch + i]; std::cout << static_cast<int>(pixel) << " "; } std::cout << "\n"; } // 转换为D2D兼容的四通道数据(B8G8R8A8_UNORM) std::vector<uint8_t> rgbaData(bitmap.width * bitmap.rows * 4); for (int y = 0; y < bitmap.rows; y++) { for (int x = 0; x < bitmap.width; x++) { uint8_t alpha = bitmap.buffer[y * bitmap.pitch + x]; // 将灰度值作为alpha,RGB设为白色(若需黑色字体,RGB设为0即可) size_t idx = (y * bitmap.width + x) * 4; rgbaData[idx] = 255; // B rgbaData[idx + 1] = 255; // G rgbaData[idx + 2] = 255; // R rgbaData[idx + 3] = alpha; // A } } auto render = static_cast<Direct2DRenderer*>(static_cast<WindowsWindow*>(Window)->GetRenderer()); D2D1_PIXEL_FORMAT format = { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED // 使用预乘alpha,配合上述RGB值 }; // 创建Bitmap时使用正确尺寸:width × rows HRESULT hr = render->GetRenderTarget()->CreateBitmap( D2D1::SizeU(bitmap.width, bitmap.rows), rgbaData.data(), bitmap.width * 4, // 每行四通道数据的字节数 D2D1::BitmapProperties(format), &Bitmap ); assert(SUCCEEDED(hr)); // 清理FreeType资源 FT_Done_Face(Face); FT_Done_FreeType(Library);
额外注意事项
- 若想直接使用单通道格式,可尝试
DXGI_FORMAT_A8_UNORM(D2D支持此格式),无需转换为四通道,创建Bitmap时设置alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED即可。 - 使用
FT_RENDER_MODE_LCD时,输出为3通道RGB数据,需对应DXGI_FORMAT_R8G8B8_UNORM格式,同时注意DPI匹配。 - 生产环境中不要依赖
assert做错误处理,应使用if (Error != 0)捕获FreeType错误,用SUCCEEDED(hr)处理Direct2D的HRESULT。
内容的提问来源于stack exchange,提问作者Lane Pope
相关产品推荐
相关产品推荐

