ぬの部屋(仮)
nu-no-he-ya
  •  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
           
       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
           
  • std::u32stringをFreeType2+HarfBuzzで描画する処理を関数化

    諸事情により、以前作成したFreeType2+HarfBuzzのコードを関数化する。

    HarfBuzzを使いまわす場合、バッファのクリアが必要となり、hb_buffer_clear_contentsを使用する。

    render_font.hpp

    #pragma once
    
    #ifdef _DEBUG
    #pragma comment(lib,"freetyped.lib")
    #pragma comment(lib,"harfbuzz.lib")
    #else
    #pragma comment(lib,"freetype.lib")
    #pragma comment(lib,"harfbuzz.lib")
    #endif
    
    #include <ft2build.h>
    #include FT_FREETYPE_H
    
    #include <hb.h>
    #include <hb-ft.h>
    
    
    
    struct Image {
        int imageWidth;
        int imageHeight;
        std::vector<unsigned char> image;
        Image(int w, int h) {
            image.resize(w * h);
            imageWidth = w;
            imageHeight = h;
        }
        //! @brief imageへの書き込み時のピクセル計算
        int pixel_pos(const int x, const int y) {
            return y * imageWidth + x;
        }
    
        bool is_valid_area(int xx, int yy) {
            if (xx < 0)return false;
            if (yy < 0)return false;
            if (xx >= imageWidth)return false;
            if (yy >= imageHeight)return false;
            return true;
        }
    };
    

    //! @brief imageへbmpの内容を書き込む
    //! @param [in] bmp 文字画像
    //! @param [in] startx image画像内の書き込み開始位置
    //! @param [in] starty image画像内の書き込み開始位置
    void draw(Image* image, const FT_Bitmap& bmp, int startx, int starty) {
    
        int Width = bmp.width;
        int Height = bmp.rows;
    
        for (size_t y = 0; y < Height; y++) {
            for (size_t x = 0; x < Width; x++) {
    
                int xx = startx + x;
                int yy = starty + y;
    
                if( image->is_valid_area(xx, yy) == false)continue;
    
                if (bmp.buffer[y * Width + x]) {
                    (image->image)[image->pixel_pos(xx, yy)] = 1;
                }
            }
        }
    
    }
    

    //! @brief フォントの読込 FreeType2の処理
    //! @param [in] library FT_Library
    //! @param [in] fontfile フォントファイルへのパス
    //! @return フェイスオブジェクト
    FT_Face* my_LoadFonts(
        FT_Library& library,
        const char* fontfile
    ) {
        FT_Face* face = new FT_Face;
        FT_Error error;
    
        // フォントファイル読み込み
        error = FT_New_Face(
            library,
            fontfile,
            0,
            face
        );
    
        //文字コード指定
        error = FT_Select_Charmap(
            *face,
            FT_ENCODING_UNICODE // エンコード指定
        );
        if (error == FT_Err_Unknown_File_Format)
            return nullptr;
        else if (error)
            return nullptr;
    
        int pixel_size_y = 64;
        error = FT_Set_Pixel_Sizes(
            *face,
            0,
            pixel_size_y);
    
        return face;
    }
    

    //! @brief HarfBuzzで計算した座標を使いFreeType2で文字列を描画する
    //! @param [in] image 描画先
    //! @param [in] hbbuf HarfBuzzオブジェクト
    //! @param [in] face FreeType2のフェイス
    void my_FaceDraw(Image* image, hb_buffer_t* hbbuf, FT_Face* face) {
    
        // 描画先をクリア
        std::fill(image->image.begin(), image->image.end(), 0);
    
        //文字数を格納 (書記素数ではない。例えば「あ゙」は2文字)
        unsigned int glyph_count;
    
        hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(hbbuf, &glyph_count);
        hb_glyph_position_t* glyph_pos = hb_buffer_get_glyph_positions(hbbuf, &glyph_count);
    
        hb_position_t cursor_x = 0;
        hb_position_t cursor_y = 0;
    
        // 各文字ごとに描画する
        for (unsigned int i = 0; i < glyph_count; i++) {
    
            // codepointという変数名だが実際にはグリフインデクスが入っている
            hb_codepoint_t glyphid = glyph_info[i].codepoint;
    
            // 一文字分のオフセット。本来描画される位置からどれぐらいずれるか
            hb_position_t x_offset = glyph_pos[i].x_offset >> 6;// 結合文字の゛は本来の位置より左側に描画するので
            hb_position_t y_offset = glyph_pos[i].y_offset >> 6;// x_offsetにはマイナスの値が入る
    
            // 次の文字の描画開始位置までのピクセル数
            hb_position_t x_advance = glyph_pos[i].x_advance >> 6;
            hb_position_t y_advance = glyph_pos[i].y_advance >> 6;
    
    
            ///////////////////////////////////////
            ///////////////////////////////////////
            ///////////////////////////////////////
            FT_Error error = FT_Load_Glyph(*face, glyphid, FT_LOAD_RENDER);
            if (error) {
                continue;
            }
            // 文字を画像化
            FT_Render_Glyph((*face)->glyph, FT_RENDER_MODE_NORMAL);
    
            // 画像書き込み
            // オフセットを加えて座標調整する
            draw(
                image,
                (*face)->glyph->bitmap,
                cursor_x + x_offset + (*face)->glyph->bitmap_left,
                cursor_y + y_offset - (*face)->glyph->bitmap_top + 100
            );
            ///////////////////////////////////////
            ///////////////////////////////////////
            ///////////////////////////////////////
    
            // 次の文字の描画開始値
            cursor_x += x_advance;
            cursor_y += y_advance;
        }
    }
    

    void render_by_font(
        Image* image,
        FT_Face* ft_face,
        const std::u32string& text,
        hb_script_t script,
        hb_buffer_t* hbbuf,
        hb_font_t* hbfont,
        std::string lang
    ) {
        // バッファの内容をクリア
        // hb_buffer_tを再利用するときは、hb_buffer_clear_contents()でバッファをクリアする
        hb_buffer_clear_contents(hbbuf);
    
        // バッファにテキストを追加
        hb_buffer_add_utf32(hbbuf, (const std::uint32_t*)text.data(), -1, 0, -1);// 描画したいテキストの設定
        hb_buffer_set_direction(hbbuf, HB_DIRECTION_LTR);                        // 文字の方向を左から右として設定
        hb_buffer_set_script(hbbuf, script);                                     // Unicodeの用字(Script)として日本語を指定
        hb_buffer_set_language(hbbuf, hb_language_from_string(lang.c_str(), -1));// 言語として日本語を設定
    
        ////////////////////////
        hb_shape(hbfont, hbbuf, NULL, 0);
        ////////////////////////
        my_FaceDraw(image,hbbuf, ft_face);//FreeType2とHarfBuzzで文字列描画
        ////////////////////////
    
    }
    

    main.cpp

    #include <iostream>
    
    #include <vector>
    #include <fstream>
    #include <filesystem>
    #include <unordered_map>
    
    #include"render_font.hpp"
    
    
    #pragma warning(disable:4996)
    
    
    #include <string>
    #include <array>
    
    
    //! @brief PBM(1byte,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む
    void pbmP1_Write(const char* const fname, const int width, const int height, const unsigned char* const p);
     
    //! @brief フォント情報を管理
    struct FaceInfo {
        FT_Face* face;      // フェイス(Freetype)
        hb_font_t* hbfont;  // フェイス(HarfBuzz)
        hb_script_t script; // Unicodeの用字(=Script)
        std::string lang;   // HarfBuzzに指定する言語
    
        FaceInfo(FT_Face* f, hb_script_t s, const char* l) : face(f), script(s), lang(l) {
            // フォントオブジェクト作成
            hbfont = hb_ft_font_create(*face, nullptr);
    
        }
        FaceInfo(FaceInfo&& fr){
            face = fr.face;
            script = fr.script;
            lang = fr.lang;
            hbfont = fr.hbfont;
            fr.face = nullptr;
            fr.hbfont = nullptr;
        }
        // フォント破棄
        void Delete() {
    
            if (hbfont)
                hb_font_destroy(hbfont);
            if (face)
                FT_Done_Face(*face);
        }
    };
    

    int
    main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; // HarfBuzzのオブジェクト作成 hb_buffer_t* hbbuf; hbbuf = hb_buffer_create(); ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 出力先を作成 Image image(300, 150); ///////////////////////////////////////////// // フォント情報作成 FaceInfo faces[3] = { FaceInfo( my_LoadFonts(library, "C:\\Windows\\Fonts\\msgothic.ttc"), HB_SCRIPT_HIRAGANA, "jp" ), FaceInfo( my_LoadFonts(library, "C:\\Windows\\Fonts\\seguiemj.ttf"), HB_SCRIPT_HIRAGANA, "jp" ), FaceInfo( my_LoadFonts(library, "C:\\Windows\\Fonts\\Times.ttf"), HB_SCRIPT_LATIN, "en" ) }; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// { // フォントを使って文字列を描画 render_by_font( &image, faces[0].face, U"あ゙いう", faces[0].script, hbbuf, faces[0].hbfont, faces[0].lang.c_str() ); pbmP1_Write("freetypetest_jp.pbm", image.imageWidth, image.imageHeight, &image.image[0]);// 結果を保存 } { // フォントを使って文字列を描画 render_by_font( &image, faces[1].face, U"👨‍👨‍👧‍👦", faces[1].script, hbbuf, faces[1].hbfont, faces[1].lang.c_str() ); pbmP1_Write("freetypetest_mj.pbm", image.imageWidth, image.imageHeight, &image.image[0]);// 結果を保存 } { // フォントを使って文字列を描画 render_by_font( &image, faces[2].face, U"àbâáăã", faces[2].script, hbbuf, faces[2].hbfont, faces[2].lang.c_str() ); pbmP1_Write("freetypetest_la.pbm", image.imageWidth, image.imageHeight, &image.image[0]);// 結果を保存 } for(auto& f : faces){ f.Delete(); } ///////////////////////////////////////////// ///////////////////////////////////////////// ///////////////////////////////////////////// // HarfBuzzのオブジェクト破棄 hb_buffer_destroy(hbbuf); // FreeType2の解放 FT_Done_FreeType(library); } //! @brief PBM(1byte,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む void pbmP1_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, "P1\n%d\n%d\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] ? 0 : 1); k++; } fprintf(fp, "\n"); } fclose(fp); }

    結果