You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:23:18