¿Ü°û¼±À» ¸Å¹ø ±×¸®¸é ºÎÇÏ°¡ °É¸®±â ¶§¹®¿¡ 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 |