ÆùÆ® ij½Ì

¿Ü°û¼±À» ¸Å¹ø ±×¸®¸é ºÎÇÏ°¡ °É¸®±â ¶§¹®¿¡ ij½ÌÇÏ¿© ±×·Á º¸ÀÚ.
ÀÌ¹Ì Çѹø ±×·ÁÁø ¹®ÀÚ´Â ´Ù½Ã FreeType ¶óÀ̺귯¸®·Î ±×¸®Áö ¾Ê°í ¸Þ¸ð¸®¿¡¼­ ºñÆ®¸Ê À̹ÌÁö¸¦ º¹»çÇÑ´Ù.

"TEST"¶õ ÆùÆ®¸¦ Ãâ·Â ÇÒ¶§ ¸¶Áö¸· ¹®ÀÚ 'T'´Â ij½Ì ¹öÆÛ¿¡ Á¸ÀçÇϱ⠶§¹®¿¡ ij½Ì ¹öÆÛ¿¡¼­ 'T' ¹®ÀÚ¸¦ º¹»çÇÑ´Ù.



"ÆùÆ® ¤Ô¤²¤Î¤ª °ª Hello, World! ¾Æ¸§´Ù¿î ¿ì¸®³ª¶ó ÆùÆ®¼¼»ó" ¹®ÀÚ¿­À» ij½Ì ¹öÆÛ¿¡ Ãâ·ÂÇßÀ» ¶§, °á°ú´Â ´ÙÀ½°ú °°´Ù.
ºñÆ®¸Ê À̹ÌÁö¸¦ ij½Ì ¹öÆÛ¿¡ ³Ö±â ¶§¹®¿¡ ÆùÆ® ºñÆ®¸ÊÀÇ °ø¹éÀÌ ¾øÀÌ »ª»ªÇÏ°Ô ¹èÄ¡ µÈ´Ù.



ÁÖ¿ä ÄÚµå´Â ´ÙÀ½°ú °°´Ù.
namespace StringShow
{
    const int FONT_MAP_WIDTH = 1024;
    const int FONT_MAP_HEIGHT = 1024;
    int m_fontSize = 0, m_fontHeight = 0, m_fontAscender = 0;
    int m_fontBoxHeight = 0;  //ij½Ì ¹öÆÛ¿¡¼­ ÆùÆ®ÀÇ ¶óÀÎÀÇ ³ôÀÌ´Ù.
    char* m_fontMap = NULL;
    Point2<int> m_pos = {0, 0};

    struct Glyph
    {
            FT_Face face;
            TCHAR ch;
            int size;
            bool operator < (const Glyph& g) const
            {
                if(face < g.face)
                    return true;
                else if(face > g.face)
                    return false;
                if(ch < g.ch)
                    return true;
                else if(ch > g.ch)
                    return false;
                if(size < g.size)
                    return true;
                return false;
            }
    };

    struct GlyphData
    {
        int advancex, advancey;
        int fontHeight; //ÆùÆ® ³ôÀÌ
        int fontAscender; //±âÁؼ±¿¡¼­ ¿Ã¶ó°£ ³ôÀÌ
        int posx, posy, width, height;
        int glyphLeft, glyphTop;
        int atlasWidth, atlasHeight;
        int use;
    };

    typedef std::map<Glyph, GlyphData> GlphContainer;   
    GlphContainer m_glyphList;

    ............


FONT_MAP_WIDTH, FONT_MAP_HEIGHTÀº ij½Ì ¹öÆÛÀÇ °¡·Î , ¼¼·Î »çÀÌÁîÀÌ´Ù.

m_fontSize´Â FT_Set_Char_Size·Î ÇÔ¼ö ȨÃâ½Ã ÆùÆ® »çÀÌÁîÀÌ´Ù.
FT_Set_Char_Size(face, 0, GetFontSize()*64, 96, 96);

m_fontHeight´Â ÆùÆ® ³ôÀÌ·Î Çà°£ Çȼ¿ °£°ÝÀÌ´Ù.
int fontHeight = face->size->metrics.height/64;

m_fontAscender´Â ±âÁؼ±¿¡¼­ ¾ó¸¶³ª ¿Ã¶ó °¬´ÂÁö Çȼ¿ Å©±âÀÌ´Ù.
int fontAscender = face->size->metrics.ascender / 64;

m_fontCacheMapÀº ÆùÆ® ij½Ì ¹öÆÛ·Î °°Àº ±Û²Ã(FT_Face, ¹®ÀÚ ÄÚµå, size)À̸é ij½Ì¹öÆÛ¿¡¼­ °¡Á®°£´Ù.

Glyph ±¸Á¶Ã¼

struct Glyph´Â ij½Ì¹öÆÛ¿¡ ÆùÆ®°¡ ÀÌ¹Ì Á¸Àç ÇÏ´ÂÁö Å° ¿ªÇÒÀ» ÇÏ´Â ±¸Á¶Ã¼ÀÌ´Ù.
¸ÊÀÇ ÀÌÁøÆ®¸®¿¡¼­ Ž»öÀ» ÇÒ ¼ö ÀÖ´Â Á¶°Ç(´ë¼Òºñ±³)À» ÁÖ±â À§ÇØ "operator <"¸¦ ÀçÁ¤ÀÇ ÇØÁØ´Ù.
bool operator < (const Glyph& g) const

GlyphÀÇ ±¸Á¶Ã¼ ¸â¹ö´Â ´ÙÀ½°ú °°´Ù.
            FT_Face face;
            TCHAR ch;  //¹®ÀÚ ÄÚµå
            int size;  //ÆùÆ® »çÀÌÁî

GlyphData ±¸Á¶Ã¼

struct GlyphData´Â Glyph ±¸Á¶Ã¼·Î °Ë»öÇÑ °á°ú °ªÀ¸·Î ºñÆ®¸Ê À̹ÌÁöÀÇ Á¤º¸¸¦ ´ã°í ÀÖ´Ù.
ij½Ì ¹öÆÛ¿¡¼­ ºñÆ®¸Ê À̹ÌÁö¸¦ º¹»çÇϱâ À§ÇÑ ÆùÆ® Á¤º¸ÀÌ´Ù.

GlyphDataÀÇ ±¸Á¶Ã¼ ¸â¹ö´Â ´ÙÀ½°ú °°´Ù.

        int advancex, advancey;   //advancey´Â ÆùÆ® ³ôÀÌ¿Í °°Àº °ªÀÌ´Ù.
        int fontHeight;         //ÆùÆ® ³ôÀÌ
        int fontAscender;      //±âÁؼ±¿¡¼­ ¿Ã¶ó°£ ³ôÀÌ
        int posx, posy, width, height;   //ij½Ì¹öÆÛ¿¡¼­ À̹ÌÁöÀÇ À§Ä¡¿Í Æø, ³ôÀÌ °ªÀÌ´Ù.
        int glyphLeft, glyphTop;  //face->glyphÀÇ bitmap_left, bitmap_top °ªÀÌ´Ù.
        int atlasWidth, atlasHeight;  //ij½Ì ¹öÆÛÀÇ Å©±â·Î GlyphData ¸â¹öÀÏ ÇÊ¿ä´Â ¾øÀ»°Í °°´Ù. Â÷ÈÄ »©µµ·Ï ÇÑ´Ù.
        int use;   //ÆùÆ®°¡ ÇöÀç »ç¿ë ÁßÀÎÁö üũÇÑ´Ù. ÀÌ Äڵ忡¼­´Â ±¸Á¶Ã¼ ¸â¹ö¸¸ Á¸ÀçÇÏ°í ¹Ì»ç¿ë ÁßÀÌ´Ù.

m_glyphList Á¤ÀÇ

Glyph ±¸Á¶Ã¼¸¦ Å°·ÎÇÏ´Â map º¯¼ö m_glyphList¸¦ Á¤ÀÇÇÑ´Ù.

    typedef std::map<Glyph, GlyphData> GlphContainer;   
    GlphContainer m_glyphList;


#define FONT_LINE_GAP 10  //Çà°£À» ÁÖ¾î ±ÛÀÚ¸¦ Àбâ ÆíÇϵµ·Ï ÇÑ´Ù.
STOREFONT_ERROR StringShow::StoreFont(char* buff, int width, int height, int x, int y, FT_Face& face, TCHAR ch, GlyphData& gd)
{
    //±Û¸®ÇÁ À妽º ±¸ÇÔ
    int index = FT_Get_Char_Index(face, ch);

    //·Îµå ±Û¸®ÇÁ
    int error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP);
    if(error)
        return FT_Load_Glyph_ERROR;

    //·£´õ¸µ
    error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
    if(error)
        return FT_Render_Glyph_ERROR;

    //È­¸é¿¡ Ãâ·ÂÇϱâ À§ÇØ bitmapÀÇ width, rows¸¦ ±¸ÇÑ´Ù.
    int bitmapWidth = face->glyph->bitmap.width;
    int bitmapHeight = face->glyph->bitmap.rows;
    char* bitmapBuff = (char*)face->glyph->bitmap.buffer;
    int bitmapLeft = face->glyph->bitmap_left;
    int bitmapTop = face->glyph->bitmap_top;

    if(( bitmapWidth  + x) > width)
        return WIDTH_OVER_ERROR;  //ÆùÆ®°¡ width À̹ÌÁö Å©±âº¸´Ù Å©´Ù.

    if(( bitmapHeight  + y) > height)
        return HEIGHT_OVER_ERROR;  //ÆùÆ®°¡ height À̹ÌÁö Å©±âº¸´Ù Å©´Ù.

    //GlyphData ¼³Á¤
    gd.advancex = face->glyph->advance.x >> 6;
    gd.advancey = GetFontHeight();
    gd.fontHeight = GetFontHeight();
    gd.fontAscender = GetFontAscender();
    gd.posx = x;
    gd.posy = y;
    gd.width = bitmapWidth;
    gd.height = bitmapHeight;
    gd.glyphLeft = bitmapLeft;
    gd.glyphTop = bitmapTop;
    gd.atlasWidth = FONT_MAP_WIDTH;
    gd.atlasHeight = FONT_MAP_HEIGHT;
    gd.use = 1;

    for (int n = 0 ; n < bitmapHeight; n++)
    {
        for(int m = 0; m < bitmapWidth; m++)
        {
            buff[width*(n + y) + m + x]  = bitmapBuff[bitmapWidth*n + m];
        }
    }

    return NONE_STORE_FONT_ERROR;
}

StringShow::GlyphData StringShow::GetFontChar(char* buff, FT_Face& face, TCHAR ch)
{
    int fontSize = GetFontSize();
    Glyph g = {face, ch, fontSize};
    GlyphData glyphData = {0, };

    GlphContainer::iterator it = m_glyphList.find(g);
    if(it != m_glyphList.end())
    {
        it->second.use = 1;
        return it->second;
    }

    Point2<int> size = {0, 0};
    STOREFONT_ERROR res = StringShow::StoreFont(buff, FONT_MAP_WIDTH, FONT_MAP_HEIGHT, m_pos.x, m_pos.y, face, ch, glyphData);
    size.x = face->glyph->bitmap.width;
    size.y = face->glyph->bitmap.rows;

    if(res == WIDTH_OVER_ERROR)
    {
        m_pos.x = 0;
        m_pos.y += StringShow::GetFontBoxHeight();
        StringShow::StoreFont(buff, FONT_MAP_WIDTH, FONT_MAP_HEIGHT, m_pos.x, m_pos.y, face, ch, glyphData);
    }
    else if(res > 0)
    {
        return glyphData;
    }

    m_pos.x += size.x;
    m_glyphList[g] = glyphData;

    return glyphData;
}

int RenderFont(char* buff, const StringShow::GlyphData& gd, int x, int y, TCHAR ch)
{
    int width = 1024;
    int height = 1024;

    const char* src = (const char *)StringShow::m_fontMap;

    //È­¸é¿¡ Ãâ·ÂÇϱâ À§ÇØ bitmapÀÇ width, rows¸¦ ±¸ÇÑ´Ù.
    int bitmapWidth = gd.width;
    int bitmapHeight = gd.height;
    char* bitmapBuff = (char *)StringShow::m_fontMap;
    int bitmapLeft = gd.glyphLeft;
    int bitmapTop = gd.glyphTop;
    int fontHeight = gd.fontHeight;

    if(( bitmapWidth  + x + bitmapLeft) > width)
        return 1;  //ÆùÆ®°¡ width À̹ÌÁö Å©±âº¸´Ù Å©´Ù.

    for (int n = 0 ; n < bitmapHeight; n++)
    {
        for(int m = 0; m < bitmapWidth; m++)
        {
            buff[width*(n + y + (gd.fontAscender-bitmapTop)) + m + x + bitmapLeft]  = src[StringShow::FONT_MAP_WIDTH*(n + gd.posy) + m + gd.posx];
        }
    }

    return 0;
}


int StringShow::DrawString(FT_Face& face, const char* szPath, TCHAR *str, char* outBuff)
{    
    Point2<int> pos = {0, 0};

    int len = (int)_tcslen(str);
    for(int n = 0; n < len; n++)
    {
        StringShow::GlyphData gd = GetFontChar(StringShow::m_fontCacheMap, face, str[n]);
        if(gd.advancex == 0 || gd.advancey == 0)
        {
            //Font¸¦ ij½Ì¹öÆÛ¿¡ ÀúÀå ÇÒ¼ö ¾øÀ»¶§ width, height´Â 0ÀÌ´Ù.
            continue;
        }

        if(RenderFont(outBuff, gd, pos.x, pos.y, str[n]) == 1)
        {
            pos.x = 0;
            pos.y += (gd.advancey + FONT_LINE_GAP);
            RenderFont(outBuff, gd, pos.x, pos.y, str[n]);
        }
        pos.x += gd.advancex;
    }
    StringShow::WritePGM(szPath, FONT_MAP_WIDTH, FONT_MAP_HEIGHT, (const char *)StringShow::m_fontMap);
    StringShow::WritePGM("out4.pgm", 1024, 1024, (const char *)outBuff);
    return 0;
}

int StringShow::SaveFont()
{
    FT_Library library;

    if (FT_Init_FreeType(&library))
        return -1;

    char* outBuff = new char[1024*1024];
    memset(outBuff, 0, 1024*1024);

    //ÆùÆ® Àбâ
    FT_Face face;
    //±Ã¼­ ÆäÀ̽º´Â batang.ttcÀÇ µÎ¹ø°¿¡ ÀÖ´Ù.
    //int error = FT_New_Face(library,"c:\\windows\\fonts\\batang.ttc", 2, &face);  
    //int error = FT_New_Face(library,"c:\\windows\\fonts\\arial.ttf", 0,&face);
    int error = FT_New_Face(library,"³ª´®°íµñ.ttf", 0, &face);
    SetFontSize(80);
   
    //ÆùÆ® Å©±â ¼³Á¤
    error = FT_Set_Char_Size(face, 0, GetFontSize()*64, 96, 96);
    //error = FT_Set_Pixel_Sizes(face, 0, 256);

    int fontBoxHeight = ::FT_MulFix(face->bbox.yMax - face->bbox.yMin, face->size->metrics.y_scale)/64;
    StringShow::SetFotBoxHeight( fontBoxHeight);

    int fontHeight = face->size->metrics.height/64;
    int fontAscender = face->size->metrics.ascender / 64;
    SetFontHeight(fontHeight);
    SetFontAscender(fontAscender);

    StringShow::DrawString(face, "test4.pgm", _T("ÆùÆ® ¤Ô¤²¤Î¤ª °ª Hello, World! ¾Æ¸§´Ù¿î ¿ì¸®³ª¶ó ÆùÆ®¼¼»ó"), outBuff);

    //face Á¤¸®
    FT_Done_Face(face);

    //Á¾·á½Ã ¶óÀ̺귯¸® Á¤¸®
    FT_Done_FreeType(library);

    delete [] outBuff;
    return 0;
}

StoreFont ÇÔ¼ö : 
FreeType ¶óÀ̺귯¸®·Î ¿Ü°û¼± ÆùÆ®¸¦ ±×¸®°í ºñÆ®¸Ê À̹ÌÁö¸¦ ij½Ã ¹öÆÛ  m_fontCacheMap)¿¡ ÀúÀåÇÏ°í ºñÆ®¸Ê À̹ÌÁö Á¤º¸´Â GlyphData¸¦ ÂüÁ¶ ¸Å°³º¯¼ö·Î ³Ñ°Ü ÁØ´Ù.
ij½Ì¹öÆÛ¿¡¼­ ÆøÀ» ³Ñ¾î°¡¸é WIDTH_OVER_ERROR °ªÀ» ¸®ÅÏÇÑ´Ù.
ij½Ì¹öÆÛ¿¡ ÀúÀå ÇÒ °ø°£ÀÌ ¾øÀ¸¸é HEIGHT_OVER_ERROR ¿¡·¯¸¦ ¸®ÅÏÇÑ´Ù.

GetFontChar ÇÔ¼ö :
m_glyphList¿¡ ºñÆ®¸Ê ÆùÆ® Á¤º¸ÀÎ GlyphData°¡ ÀÖ´ÂÁö °Ë»öÇÑ´Ù.
ÀÌ¹Ì ÆùÆ®°¡ ÀÖÀ¸¸é ÆùÆ® ºñÆ®¸Ê Á¤º¸¸¦ ¸®ÅÏÇÑ´Ù.
ÆùÆ®°¡ ¾øÀ¸¸é StoreFont ÇÔ¼ö·Î ij½Ì¹öÆÛ¿¡ ÆùÆ® À̹ÌÁö¿Í ÆùÆ® Á¤º¸¸¦ Ãß°¡ÇÑ´Ù.
StoreFont ÇÔ¼ö È£Ãâ½Ã ÆøÀ» ³Ñ¾î°¡¸é ´ÙÀ½¶óÀÎÀ¸·Î À̵¿ ÈÄ StoreFont ´Ù½Ã ½ÇÇàÇÑ´Ù.

RenderFont ÇÔ¼ö :
GlyphData¸¦ ÀÌ¿ëÇÏ¿© ÆùÆ®¸¦ Ãâ·Â ¹öÆÛ¿¡ ±×¸°´Ù.

DrawString ÇÔ¼ö :
¹®ÀÚ¿­À» Ãâ·ÂÇÑ´Ù.
GetFontChar·Î GlyphData¸¦ ±¸ÇÏ°í RenderFont·Î ¹®ÀÚ¸¦ ·»´õ¸µ ÇÑ´Ù.
GlyphDataÀÇ advancex, advancey °ªÀÌ 0À̸é ij½Ì¹öÆÛ¿¡ ¹®ÀÚ ¾ø±â ¶§¹®¿¡ ±×¸®Áö ¾Ê´Â´Ù.

if(gd.advancex == 0 || gd.advancey == 0)
{
        continue;
}

ij½Ì ¹öÆÛ¸¦ À̹ÌÁö·Î ÀúÀåÇÑ´Ù.
StringShow::WritePGM(szPath, FONT_MAP_WIDTH, FONT_MAP_HEIGHT, (const char*)StringShow::m_fontCacheMap);

ÃÖÁ¾ Ãâ·Â¸¦ "out4.pgm" À̹ÌÁö·Î ÀúÀåÇÑ´Ù.
StringShow::WritePGM("out4.pgm", 1024, 1024, (const char *)outBuff);

¼Ò½º : 04_string_draw.cpp
ÇÁ·ÎÁ§Æ® : font_string.zip

Âü°í)
http://soen.kr/lecture/library/freetype/ft3.htm
https://bab2min.tistory.com/322