ぬの部屋(仮)
nu-no-he-ya
  • 1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • FreeType2で文字のアウトラインを描く

    FT_Glyph_StrokeBorderを呼び出して描画する場合に比べ、FT_Glyph_StrokeBorderを呼び出さずに描画した場合のほうが文字が細くなる。

    それを利用して、一度太く書いた場所と同じ場所に細く書くことでアウトラインを描画する。

    気を付けるのは、FT_Glyph_StrokeBorderあり、なしで文字が入るボックスのサイズが異なってしまうので、top,leftを見て位置合わせが必要になる。

    #include <vector>
    
    #include <ft2build.h>
    #include FT_FREETYPE_H
    
    #include <freetype/ftstroke.h>
    
    #pragma warning(disable:4996)
    
    #pragma comment(lib,"freetype.lib")
    
    
    //! @brief PGM(1byte,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む
    void pgmP1_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII
    
        FILE* fp = fopen(fname, "wb");
        fprintf(fp, "P2\n%d %d\n255\n", width, height);
    
        size_t k = 0;
        for (size_t i = 0; i < (size_t)height; i++) {
            for (size_t j = 0; j < (size_t)width; j++) {
                fprintf(fp, "%d ", p[k] );
                k++;
            }
            fprintf(fp, "\n");
        }
    
        fclose(fp);
    }
    
    
    struct image_t {
        std::vector<unsigned char> buffer;
        int width;
        int height;
        int top;
        int left;
    };
    
    // https://stackoverflow.com/questions/20874056/draw-text-outline-with-freetype
    
    
    // library FT_Library
    // face FT_Face
    // character レンダリングする文字のコードポイント
    // img 画像の出力先

    // thickness アウトラインの太さをピクセルで指定

    // is_strokeborder strokeborderを呼ぶかどうか(初回・呼ぶ、二回目・呼ばない)
    int draw_stroker(FT_Library& library, FT_Face& face, FT_ULong character, image_t& img,int thickness ,bool is_strokeborder) { // initialize stroker, so you can create outline font FT_Stroker stroker; FT_Stroker_New(library, &stroker); // 2 * 64 result in 2px outline FT_Stroker_Set(stroker, thickness * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); /////////////////////////////////////////////// /////////////////////////////////////////////// // generation of an outline for single glyph: FT_UInt glyphIndex = FT_Get_Char_Index(face, character); FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT); if (error) return -1; // ignore errors /////////////////////////////////////////////// /////////////////////////////////////////////// FT_Glyph glyph; FT_Get_Glyph(face->glyph, &glyph); if (is_strokeborder) { FT_Glyph_StrokeBorder(&glyph, stroker, false, true); } FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, true); FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph); // blit the glyph here on your target surface. // For positioning use bitmapGlyph->left, bitmapGlyph->top // For iteration over the glyph data use bitmapGlyph->bitmap.buffer, bitmapGlyph->bitmap.width, bitmapGlyph->bitmap.rows, bitmapGlyph->bitmap.pitch. if (is_strokeborder) { img.width = bitmapGlyph->bitmap.width;; img.height = bitmapGlyph->bitmap.rows; img.top = bitmapGlyph->top; img.left = bitmapGlyph->left; for (size_t i = 0; i < img.width * img.height; i++) { // 白黒反転して保存。これで背景が白になる img.buffer.push_back(255 - bitmapGlyph->bitmap.buffer[i]); } } else { // strokeborderしないほうが画像が小さいので画像のサイズが異なる // 左側と上側にオフセットを設けるために位置の差を求める int hw = bitmapGlyph->left - img.left; int hh = img.top - bitmapGlyph->top; int notBorderW = bitmapGlyph->bitmap.width; int notBorderH = bitmapGlyph->bitmap.rows; for (size_t x = 0; x < notBorderW; x++) { for (size_t y = 0; y < notBorderH; y++) { int p = y * notBorderW + x; // strokeborderしないで描かれた領域はくりぬきたいので // その部分を白く塗る。 // しかしグレースケール、アンチエイリアスで描かれているので // ただ255にせず色を足すことでアンチエイリアスを保つ if (bitmapGlyph->bitmap.buffer[p] != 0) { int s = (y+hh) * img.width + (x+hw); img.buffer[s] += bitmapGlyph->bitmap.buffer[p]; } } } } }
    
          
    int main()
    {
    
        FT_Library  library; // handle to library
        FT_Error error;
    
        error = FT_Init_FreeType(&library);
        if (error)
            return -1;
    
        FT_Face face;      // handle to face object
    
        // フォントファイル読み込み
        error = FT_New_Face(
            library,
            "C:\\Windows\\Fonts\\meiryo.ttc",
            0,
            &face
        );
    
        //文字コード指定
        error = FT_Select_Charmap(
            face,               // target face object
            FT_ENCODING_UNICODE // エンコード指定
        );
    
    
        if (error == FT_Err_Unknown_File_Format)
            return -1;
        else if (error)
            return -1;
    
        //この二つの値でフォントサイズ調整
        FT_F26Dot6 fontsize = 16 * 64*3;
        FT_UInt CHAR_RESOLUTION = 300;
        error = FT_Set_Char_Size(
            face,                // handle to face object
            0,                   // char_width in 1/64th of points
            fontsize,            // char_height in 1/64th of points
            CHAR_RESOLUTION,     // horizontal device resolution
            CHAR_RESOLUTION);    // vertical device resolution
    
          // 文字の取得
        FT_ULong character = wchar_t(L'あ');
    
    
        /////////////////////////////
        image_t img;
        // FT_Glyph_StrokeBorder の呼び出しの有無で二回呼び出す
        draw_stroker(library, face, character,img,5,true);
        draw_stroker(library, face, character, img,5, false);
    
    
        int Width = img.width;
        int Height = img.height;
        pgmP1_Write(// ファイル保存
            "C:\\test\\freetypetest.pgm",
            Width,
            Height,
            img.buffer.data()
        );
    
        // FreeType2の解放
        FT_Done_Face(face);
        FT_Done_FreeType(library);
    }