从 FreeType 位图创建 Direct2D 位图的正确方法

问题描述 投票:0回答:1

我正在创建一个 UI 引擎并处理字体渲染。我刚刚开始并尝试实现 FreeType 来初始加载和渲染 .ttf 文件。 这是我用于加载 .ttf 并创建 Direct2D 位图的代码:

    FT_Error Error = FT_Init_FreeType(&Library);
    assert(!Error);
    FT_Face Face;
    Error = FT_New_Face(Library, "Roboto.ttf", 0, &Face);
    assert(!Error);
    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 Index = FT_Get_Char_Index(Face, TEXT('L'));
    std::cout << "\tCharacter 'L' is at index " << Index << "\n";
    Error = FT_Load_Glyph(Face, Index, 0);
    assert(!Error);
    Error = FT_Render_Glyph(Face->glyph, FT_RENDER_MODE_NORMAL);
    assert(!Error);
    
    for (int i = 0; i < Face->glyph->bitmap.pitch; i++)
    {
        for (int j = 0; j < Face->glyph->bitmap.rows; j++)
        {
            std::cout << (uint8)Face->glyph->bitmap.buffer[i + j];
        }
    }
    FT_Bitmap FTBitmap;
    FT_Bitmap_New(&FTBitmap);
    FT_Bitmap Src = Face->glyph->bitmap;
    Error = FT_Bitmap_Convert(Library, &Src, &FTBitmap, 8);
    assert(!Error);
    
    auto render = static_cast<Direct2DRenderer*>(static_cast<WindowsWindow*>(Window)->GetRenderer());
    D2D1_PIXEL_FORMAT format;
    format.format = DXGI_FORMAT_B8G8R8A8_UNORM; // I have tried using R8_UNORM but it is not supported
    format.alphaMode = D2D1_ALPHA_MODE_IGNORE;
    render->GetRenderTarget()->CreateBitmap(D2D1::SizeU(FTBitmap.width, FTBitmap.pitch), FTBitmap.buffer, FTBitmap.pitch, D2D1::BitmapProperties(format), &Bitmap);
    FT_Bitmap_Done(Library, &FTBitmap);

这似乎有效......但是当我渲染位图时,我得到这个结果: enter image description here

我已经尝试过许多 D2D 像素格式,尝试过 FT_RENDER_MODE_LCD(3x8 位通道)和 FT_RENDER_MODE_NORMAL(1x8 位通道),但要么我不完全理解这一点,要么我从一开始就做错了。任何帮助表示赞赏。还尝试过修改 FT_Set_Char_Size 值、D2D 像素格式值和 FT_Render_Glyph 值,但没有任何改变,无论如何也不认为它应该改变。

(Direct2DRenderer 类只是 HwndRenderTarget 的包装器,并不断渲染帧。另外,我发布的代码只是我试图让它工作,而不是传送代码,我知道它不漂亮!)

graphics direct2d freetype
1个回答
0
投票

freetype 字形位图本质上是一个不透明蒙版,它是每个像素 1 字节(0-255 级别),就像 Alpha 通道位图。

Direct2D 的 ID2D1HwndRenderTarget 仅支持有限的一组格式,最有用的是 DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED,因此每像素格式 4 字节 (BGRA)。

以下是将字形格式转换为 Direct2D ID2D1Bitmap 的方法(省略错误检查):

auto bmpSize = D2D1::SizeU(ftb.width, ftb.rows);
D2D1_BITMAP_PROPERTIES props{};
props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;

// build a memory buffer (1 pixel => 4 bytes)
// from glyph bitmap (1 pixel => 1 byte)
auto bits = new unsigned char[ftb.width * 4 * ftb.rows];
for (unsigned int row = 0; row < ftb.rows; row++)
{
  auto ptr = (unsigned int*)bits + row * ftb.pitch;
  for (unsigned int i = 0; i < ftb.width; i++)
  {
    auto opacity = (unsigned int)ftb.buffer[row * ftb.pitch + i];
    *ptr = opacity << 24; // ARGB format with A = opacity from glyph
    ptr++;
  }
}

ID2D1Bitmap* bmp;
m_pRenderTarget->CreateBitmap(bmpSize, (const void*)bits, ftb.width * 4, props, &bmp);
delete[] bits;
...
// do some work with bitmap ...
...
bmp->Release();
© www.soinside.com 2019 - 2024. All rights reserved.