ÄÚÄÚ½º¿¡ ÀÖ´Â ¿Ü°û¼±À» Ç¥½ÃÇÏ´Â Äڵ带 ºÐ¼®ÇÑ´Ù. Ãâ·ÂµÈ À̹ÌÁö¸¦ ¸ÕÀú º¸ÀÚ. TestOutline2 ÇÔ¼ö¿¡¼ FreeTypeÀ» ÃʱâÈ ÇÏ°í ÆùÆ®¸¦ ±×¸°´Ù. int TestOutline2()
{ if (FT_Init_FreeType(&s_library)) return -1; //ÆùÆ® Àбâ FT_Face face; //int error = FT_New_Face(s_library,"³ª´®°íµñ.ttf", 0, &face); int error = FT_New_Face(s_library,"c:\\windows\\fonts\\arial.ttf", 0,&face); //ÆùÆ® Å©±â ¼³Á¤ error = FT_Set_Char_Size(face, 0, 256*64, 96, 96); Word word; word.Reset(); word.m_code = TEXT('A'); DrawFontBorder(face, word, 0xFF0000, 0xFF, 10); //face Á¤¸® FT_Done_Face(face); // ¶óÀ̺귯¸® Á¤¸® FT_Done_FreeType(s_library); if(word.m_buffer) { WriteTGA("test_outline2.tga", word.m_buffer, word.m_width, word.m_height); delete [] word.m_buffer; word.m_buffer = NULL; } return 0; } DrawFontBorder ÇÔ¼ö¿¡¼ ÆùÆ®¸¦ ±×¸°´Ù. bool
DrawFontBorder(FT_Face& face, Word& word, unsigned int
color1, unsigned int color2, unsigned int border) bool DrawFontBorder(FT_Face& face, Word& word,
unsigned int color1, unsigned int color2, unsigned
int border)
{ FT_UInt index = FT_Get_Char_Index(face, FT_ULong(word.m_code)); if (!index) return false; if (FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP)) return false; FT_Glyph glyph; if (FT_Get_Glyph(face->glyph, &glyph)) return false; FT_Stroker stroker; if (FT_Stroker_New(s_library, &stroker)) return false; FT_Stroker_Set(stroker, (int)(border * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); if (FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1)) return false; FT_Outline *outline = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline; FT_BBox bbox; FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_GRIDFIT, &bbox); int width = (bbox.xMax - bbox.xMin) >> 6; // 64·Î ³ª´©±â int rows = (bbox.yMax - bbox.yMin) >> 6; FT_Bitmap *bitmap = &face->glyph->bitmap; //¸®ÅÏÇÒ Á¤º¸¸¦ ¼³Á¤ÇÑ´Ù. word.m_width = width; word.m_height = rows; word.m_drawX = face->glyph->metrics.horiBearingX >> 6; word.m_drawY = face->glyph->metrics.horiBearingY >> 6; word.m_advanceX = face->glyph->metrics.horiAdvance >> 6; word.m_buffer = new unsigned char[word.m_width * word.m_height * 4]; memset(word.m_buffer, 0, word.m_width * word.m_height * 4); unsigned char* buffer = word.m_buffer; FT_Raster_Params params; FT_Bitmap bmp; //¿Ü°û¿ë ÆùÆ®¸¦ ±×¸°´Ù. bmp.buffer = new unsigned char[width * rows]; memset(bmp.buffer, 0, width * rows); bmp.width = width; bmp.rows = rows; bmp.pitch = width; bmp.pixel_mode = FT_PIXEL_MODE_GRAY; bmp.num_grays = 256; memset(& params, 0, sizeof ( params)); params.source = outline; params.target = &bmp; params.flags = FT_RASTER_FLAG_AA; FT_Outline_Translate(outline,-bbox.xMin,-bbox.yMin); FT_Outline_Render(s_library, outline, ¶ms); //rasterize font unsigned char* buffer1 = bmp.buffer; //³»ºÎ ÆùÆ®¸¦ ±×¸°´Ù. FT_BBox bbox_in; FT_Glyph glyph_fg; FT_Get_Glyph(face->glyph, &glyph_fg); FT_Glyph_Get_CBox(glyph_fg, FT_GLYPH_BBOX_GRIDFIT,&bbox_in); bmp.buffer = new unsigned char[width * rows]; memset(bmp.buffer, 0, width * rows); bmp.width = width; bmp.rows = rows; bmp.pitch = width; bmp.pixel_mode = FT_PIXEL_MODE_GRAY; bmp.num_grays = 256; outline = &reinterpret_cast<FT_OutlineGlyph>(glyph_fg)->outline; memset(& params, 0, sizeof ( params)); params.source = outline; params.target = &bmp; params.flags = FT_RASTER_FLAG_AA; FT_Outline_Translate(outline,-bbox.xMin,-bbox.yMin); FT_Outline_Render(s_library, outline, ¶ms); //rasterize font unsigned char* buffer2 = bmp.buffer; int pitch = width; for ( int yy = 0; yy < rows; ++yy) { for ( int xx = 0; xx < width; ++xx) { //¿Ü°û¼± ºñÆ®¸Ê ÆùÆ®¸¦ ÁöÁ¤ Ä®¶ó·Î ±×¸°´Ù. int si = yy * word.m_width * 4 + xx * 4; int alpha1 = buffer1[yy * pitch + xx]; unsigned char sr = (color1 & 0xFF0000) >> 16, sg = (color1 & 0xFF00 ) >> 8, sb = (color1 & 0xFF ); unsigned char dr = (color2 & 0xFF0000) >> 16, dg = (color2 & 0xFF00 ) >> 8, db = (color2 & 0xFF ); if (alpha1) { buffer[si + 0] = dr; buffer[si + 1] = dg; buffer[si + 2] = db; buffer[si + 3] = alpha1; } //³»ºÎ ºñÆ®¸Ê ÆùÆ®¸¦ ÁöÁ¤ Ä®¶ó·Î ±×¸°´Ù. int alpha2 = buffer2[yy * pitch + xx]; if (alpha2) { buffer[si + 0] = dr + ( sr - dr) * alpha2 / 255.0f; buffer[si + 1] = dg + ( sg - dg) * alpha2 / 255.0f; buffer[si + 2] = db + ( sb - db) * alpha2 / 255.0f; buffer[si + 3] = min(255, alpha1 + alpha2); } } } delete [] buffer1; delete [] buffer2; FT_Stroker_Done(stroker); FT_Done_Glyph(glyph); return true; } ÇÔ¼ö¿¡¼ »ç¿ëµÇ´Â ¸Å°³º¯¼ö Word´Â ´ÙÀ½°ú °°´Ù. struct Word
{ FT_ULong m_code; int m_width; int m_height; int m_drawX; int m_drawY; int m_advanceX; unsigned char* m_buffer; void Reset() { m_code = 0; m_width = 0; m_height = 0; m_drawX = 0; m_drawY = 0; m_advanceX = 0; //FT_Glyph_MetricsÀÇ horiAdvance °ªÀÌ´Ù. ¼öÆò ÁøÇàÆø m_buffer = NULL; } }; ÁøÇàÆø : ÇöÀç ±ÛÀÚ¿¡¼ ´ÙÀ½ ±ÛÀÚ¸¦ ±×¸®±â À§ÇØ À̵¿ÇØ¾ß ÇÒ °Å¸®ÀÌ´Ù. 1. ±Û¸®ÇÁ ¿ÀºêÁ§Æ® °¡Á®¿À±â ¹®ÀÚ ÄÚµå·Î ±Û¸®ÇÁ À妽º¸¦ ±¸ÇÑ´Ù. ±Û¸®ÇÁ À妽º·Î ±Û¸®ÇÁ¸¦ ·ÎµùÇÑ´Ù. ·ÎµùÇÑ ±Û¸®ÇÁ ½½·Ô¿¡¼ ±Û¸®ÇÁ ¿ÀºêÁ§Æ®¸¦ »ý¼ºÇÑ´Ù. FT_UInt index = FT_Get_Char_Index(face, FT_ULong(word.m_code));
if (!index) return false; if (FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP)) return false; FT_Glyph glyph; if (FT_Get_Glyph(face->glyph, &glyph)) return false; ¹®ÀÚ Äڵ忡 ÇØ´çÇÏ´Â ±Û¸®ÇÁ À妽º¸¦ ±¸ÇÑ´Ù. FT_UInt FT_Get_Char_Index( FT_Face face, FT_ULong charcode ) ÇØ´ç ±Û¸®ÇÁ À妽º¸¦ face¿¡ ·ÎµùÇÑ´Ù. FT_Error FT_Load_Glyph( FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags ) ±Û¸®ÇÁ ½½·ÔÀ¸·Î ºÎÅÍ ±Û¸®ÇÁ (º¤ÅÍ)À̹ÌÁö ¿ÀºêÁ§Æ®¸¦ °¡Á®¿Â´Ù. FT_Done_Glyph·Î ÇØÁ¦ µÇ¾î¾ß ÇÑ´Ù. FT_Error FT_Get_Glyph( FT_GlyphSlot slot, FT_Glyph *aglyph ) 2. ¿Ý°û¼±À» ±×¸®±â À§ÇØ ½ºÆ®·ÎÅ© °´Ã¼¸¦ ¸¸µé°í FT_Outline °´Ã¼¸¦ ¾ò¾î¿Â´Ù. FT_Stroker stroker;
if (FT_Stroker_New(s_library, &stroker)) return false; FT_Stroker_Set(stroker, (int)(border * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); if (FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1)) return false; FT_Outline *outline = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline; FT_Stroker_Set : border ¶óÀÎ µÎ²²ÀÌ´Ù. FT_Glyph_StrokeBorder : glyph¿¡ Stroker¸¦ ¼³Á¤ÇÑ´Ù. FT_Outline_Render¿¡ ÇÊ¿äÇÑ FT_Outline °´Ã¼¸¦ ±¸ÇÑ´Ù. 3. ¸®ÅÏÇÒ Á¤º¸¸¦ ¼³Á¤ÇÑ´Ù. FT_BBox bbox;
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_GRIDFIT, &bbox); int width = (bbox.xMax - bbox.xMin) >> 6; // 64·Î ³ª´©±â int rows = (bbox.yMax - bbox.yMin) >> 6; FT_Bitmap *bitmap = &face->glyph->bitmap; //¸®ÅÏÇÒ Á¤º¸¸¦ ¼³Á¤ÇÑ´Ù. word.m_width = width; word.m_height = rows; word.m_drawX = face->glyph->metrics.horiBearingX >> 6; word.m_drawY = face->glyph->metrics.horiBearingY >> 6; word.m_advanceX = face->glyph->metrics.horiAdvance >> 6; word.m_buffer = new unsigned char[word.m_width * word.m_height * 4]; memset(word.m_buffer, 0, word.m_width * word.m_height * 4); unsigned char* buffer = word.m_buffer; ¿©±â¼ FT_Glyph_Get_CBox´Â ¿Ü°û¼±À» ±×¸®±â À§ÇÑ ¹Ú½º¸¦ ±¸ÇÏ°í bbox´Â ¿Ü°û¼±À» ±×¸±¶§ »ç¿ëµÈ´Ù. FT_GLYPH_BBOX_PIXELS·Î ÁöÁ¤Çϸé 64·Î ³ª´²ÁÙ ÇÊ¿ä°¡ ¾ø´Âµ¥ ¿Ö FT_GLYPH_BBOX_GRIDFITÀ¸·Î ÇÏ´ÂÁö´Â ÀÌÇØ°¡ ¾ÈµÊ int width = (bbox.xMax - bbox.xMin) >> 6; int rows = (bbox.yMax - bbox.yMin) >> 6; 4. ¿Ü°û¿ë ÆùÆ®¸¦ ±×¸°´Ù. FT_Raster_Params params;
FT_Bitmap bmp; //¿Ü°û¿ë ÆùÆ®¸¦ ±×¸°´Ù. bmp.buffer = new unsigned char[width * rows]; memset(bmp.buffer, 0, width * rows); bmp.width = width; bmp.rows = rows; bmp.pitch = width; bmp.pixel_mode = FT_PIXEL_MODE_GRAY; bmp.num_grays = 256; memset(& params, 0, sizeof ( params)); params.source = outline; params.target = &bmp; params.flags = FT_RASTER_FLAG_AA; FT_Outline_Translate(outline,-bbox.xMin,-bbox.yMin); FT_Outline_Render(s_library, outline, ¶ms); //rasterize font unsigned char* buffer1 = bmp.buffer; FT_Outline_Translate : ÆùÆ®¸¦ ±×¸±¶§ bboxÀÇ ÃÖ¼Ò°ª¸¸Å À̵¿ ½ÃŲ´Ù. FT_Outline_Render : ½ºÄµ º¯È¯À» »ç¿ëÇÏ¿© À±°û¼±À» ºñÆ®¸ÊÀ» Ãâ·ÂÇÑ´Ù. 5. ³»ºÎ ÆùÆ®¸¦ ±×¸°´Ù. //³»ºÎ ÆùÆ®¸¦ ±×¸°´Ù.
FT_BBox bbox_in; FT_Glyph glyph_fg; FT_Get_Glyph(face->glyph, &glyph_fg); FT_Glyph_Get_CBox(glyph_fg, FT_GLYPH_BBOX_GRIDFIT,&bbox_in); bmp.buffer = new unsigned char[width * rows]; memset(bmp.buffer, 0, width * rows); bmp.width = width; bmp.rows = rows; bmp.pitch = width; bmp.pixel_mode = FT_PIXEL_MODE_GRAY; bmp.num_grays = 256; outline = &reinterpret_cast<FT_OutlineGlyph>(glyph_fg)->outline; memset(& params, 0, sizeof ( params)); params.source = outline; params.target = &bmp; params.flags = FT_RASTER_FLAG_AA; FT_Outline_Translate(outline,-bbox.xMin,-bbox.yMin); FT_Outline_Render(s_library, outline, ¶ms); //rasterize font unsigned char* buffer2 = bmp.buffer; 6. ÃÖÁ¾ÀûÀ¸·Î ¾Æ¿ì¶óÀÎÀÌ ÀÖ´Â Ä®¶ó ºñÆ®¸ÊÀ» Ãâ·ÂÇÑ´Ù. int pitch = width;
for ( int yy = 0; yy < rows; ++yy) { for ( int xx = 0; xx < width; ++xx) { //¿Ü°û¼± ºñÆ®¸Ê ÆùÆ®¸¦ ÁöÁ¤ Ä®¶ó·Î ±×¸°´Ù. int si = yy * word.m_width * 4 + xx * 4; int alpha1 = buffer1[yy * pitch + xx]; unsigned char sr = (color1 & 0xFF0000) >> 16, sg = (color1 & 0xFF00 ) >> 8, sb = (color1 & 0xFF ); unsigned char dr = (color2 & 0xFF0000) >> 16, dg = (color2 & 0xFF00 ) >> 8, db = (color2 & 0xFF ); if (alpha1) { buffer[si + 0] = dr; buffer[si + 1] = dg; buffer[si + 2] = db; buffer[si + 3] = alpha1; } //³»ºÎ ºñÆ®¸Ê ÆùÆ®¸¦ ÁöÁ¤ Ä®¶ó·Î ±×¸°´Ù. int alpha2 = buffer2[yy * pitch + xx]; if (alpha2) { buffer[si + 0] = dr + ( sr - dr) * alpha2 / 255.0f; buffer[si + 1] = dg + ( sg - dg) * alpha2 / 255.0f; buffer[si + 2] = db + ( sb - db) * alpha2 / 255.0f; buffer[si + 3] = min(255, alpha1 + alpha2); } } } word.m_width¿Í width´Â °°Àº °ªÀÌ´Ù. buffer : ºñÆ®¸ÊÀ» Ãâ·ÂÇÒ ¹öÆÛ buffer1: ¿Ü°û¼±¿ë 256 ±×·¹ÀÌ ¹öÆÛ buffer2: ³»ºÎ 256 ±×·¹ÀÌ ¹öÆÛ 7. ¸®¼Ò½º¸¦ ÇØÁ¦ÇÑ´Ù. delete [] buffer1;
delete [] buffer2; FT_Stroker_Done(stroker); FT_Done_Glyph(glyph); ´Ù¿î·Îµå: outline_cocos.cpp ÂüÁ¶) http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html http://www.soen.kr/lecture/library/freetype/ft2.htm http://www.soen.kr/lecture/library/freetype/ft3.htm http://www.cppblog.com/shly/archive/2013/12/07/204638.html http://www.cppblog.com/wc250en007/archive/2011/07/13/150812.html |