freetype中的RGB像素格式

时间:2014-06-01 17:00:37

标签: c++ freetype

我很难理解像素在freetype下的存储方式,我的问题的核心部分是如何在渲染字形后提取RGB值。

typedef uint32_t Tindex;
//
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_LCD);
//
FT_Bitmap bitmap = face->glyph->bitmap;
FT_Glyph_Metrics metrics = face->glyph->metrics;
//
Tindex colStartPos = metrics.horiBearingX >> 6;
Tindex rowStartPos = metrics.horiBearingY >> 6;
//
for (Tindex y = 0; y < bitmap.rows; y = y + 3)
{
    Tindex row = rowStartPos + y;
    for (Tindex x = 0; x < bitmap.width; x = x + 3)
    {
        Tindex col = colStartPos + x;
        uint8_t r = bitmap.buffer[y * bitmap.width + x];
        uint8_t g = bitmap.buffer[y * bitmap.width + x + 1];
        uint8_t b = bitmap.buffer[y * bitmap.width + x + 2];
        img(col, row) = pixel{r, g, b, 255};
        // img and pixel are placeholders to simplify the code
    }
}

官方文档没有指定像素的存储方式,只是说格式是RGB,我的编译器也说明从bitmap.buffer检索的值的类型是float但这可能是某种打字技术的结果。

我注意到,当在FT_RENDER_MODE_LCD中渲染时,迭代次数被重复三次以便数学检查出来,但我不明白我做错了什么,这个片段只是一个在我做过的许多尝试中。

另请注意,bitmap.pitch / bitmap.rows在我的情况下等于1,我希望它是3

有人可以解释我应该如何读取像素值吗?可以切换到RGBA格式吗?

从文档中看,格式为 interleaved ,但它看起来不像


这段代码使用了boost,libpng和freetype,它重现了我遇到的问题,并且它是自包含的(不要忘记自定义ttf字体的路径)

#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/io/png_dynamic_io.hpp>
extern "C" {
#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
#include <ft2build.h>
#include FT_FREETYPE_H
#include <ftlcdfil.h>
}
#include <cstdint>
#define FONTFILE "/tmp/DroidSans.ttf"
#define IMGSIZE 400
typedef uint32_t Tindex;
int main()
{
    FT_Library library = 0;
    FT_Face face = 0;
    FT_Init_FreeType(&library);
    FT_Library_SetLcdFilter(library, FT_LCD_FILTER_LIGHT);
    FT_New_Face(library, FONTFILE, 0, &face);
    FT_Set_Char_Size(face, 0, 24 * 64, 300, 300);
    FT_ULong charcode = 0x003f;
    FT_UInt glyph_index = 0;
    glyph_index = FT_Get_Char_Index(face, charcode);
    FT_Load_Glyph(face, glyph_index, FT_LOAD_TARGET_NORMAL);
    FT_Render_Glyph(face->glyph, FT_RENDER_MODE_LCD);
    FT_Bitmap bitmap = face->glyph->bitmap;
    FT_Glyph_Metrics metrics = face->glyph->metrics;
    Tindex colStartPos = metrics.horiBearingX / 64;
    Tindex rowStartPos = metrics.horiBearingY / 64;
    boost::gil::rgba8_image_t img{IMGSIZE, IMGSIZE};
    boost::gil::rgba8_image_t::view_t imgView{boost::gil::view(img)};
    for (Tindex y = 0; y < bitmap.rows; y++)
    {
        Tindex row = rowStartPos + y;
        for (Tindex x = 0; x < bitmap.width; x++)
        {
            Tindex col = colStartPos + x;
            uint8_t r = bitmap.buffer[y * bitmap.pitch + x * 3];
            uint8_t g = bitmap.buffer[y * bitmap.pitch + x * 3 + 1];
            uint8_t b = bitmap.buffer[y * bitmap.pitch + x * 3 + 2];
            imgView(col, row) = boost::gil::rgba8_pixel_t{r, g, b, 255};
        }
    }
    boost::gil::png_write_view("img.png", imgView);
}

我用

编译它
g++ -std=c++11 $(freetype-config --cflags) main.cpp -lpng $(freetype-config --libs)

2 个答案:

答案 0 :(得分:1)

来自文档(http://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html#FT_Bitmap)的AFAIU你的循环应该是这样的:

for (Tindex y = 0; y < bitmap.rows; y++)
{
    Tindex row = rowStartPos + y;
    for (Tindex x = 0; x < bitmap.width; x++)
    {
        Tindex col = colStartPos + x;
        uint8_t r = bitmap.buffer[y * bitmap.pitch + x*3];
        uint8_t g = bitmap.buffer[y * bitmap.pitch + x*3 + 1];
        uint8_t b = bitmap.buffer[y * bitmap.pitch + x*3 + 2];
        img(col, row) = pixel{r, g, b, 255};
        // img and pixel are placeholders to simplify the code
    }
}

答案 1 :(得分:0)

documentation表示默认FT_PIXEL_MODE_GRAY每个像素存储在1个字节中,表示灰色阴影。您可以手动将其转换为RGBA,也可以使用某些Freetype功能,例如FT_PIXEL_MODE_LCDFT_Bitmap_Convert()。我自己也没试过。