ぬの部屋(仮)
nu-no-he-ya
  •     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
           
       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
           
  • フォントを交換しながら一つの文字列を描画する

    日本語や絵文字などが混同している場合、フォントを切り替えなければ文字を描画できない。

    そこで、描画する文字列を書記素単位にし、書記素にスクリプト=用字=文字の種類の情報を付与して、スクリプトからフォントを引ける辞書を作成する。

    #include <iostream>
    #include <vector>
    #include <string>
    #include <unordered_map>
    
    
    #include "u16_to_u32.hpp"
    #include "render_font.hpp"
    
    
    #pragma warning(disable:4996)
    
    //! @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);
    }
    
    
    
    // フォントのオブジェクト
    struct FT_HB_Font {
        FT_Face *ftface;   
        hb_font_t* hbfont;
        std::string lang;
    
        FT_HB_Font(FT_Face* face,const std::string& language){
            ftface = face;                                // FreeTypeのフォントオブジェクト
            hbfont = hb_ft_font_create(*ftface, nullptr); // HarfBuzzのフォントオブジェクト
            lang = language;                              // HarfBuzz用の言語
        }
        FT_HB_Font():ftface(nullptr),hbfont(nullptr){}
    
        void Delete(){
            if (ftface) {
                FT_Done_Face(*ftface);
                ftface = nullptr;
            }
            if (hbfont) {
                hb_font_destroy(hbfont);
                hbfont = nullptr;
            }
        }
    };
    
    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();
    
        //////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////
    
        // Script(用字)に応じたフォントをマップに登録
        std::unordered_map< int, FT_HB_Font> script_map;
        script_map[HB_SCRIPT_HIRAGANA] = FT_HB_Font(my_LoadFonts(library, "C:\\Windows\\Fonts\\msgothic.ttc"),"jp");
        script_map[HB_SCRIPT_HAN]      = script_map[HB_SCRIPT_HIRAGANA];
        script_map[HB_SCRIPT_KATAKANA] = script_map[HB_SCRIPT_HIRAGANA];
        script_map[HB_SCRIPT_LATIN]    = FT_HB_Font(my_LoadFonts(library, "C:\\Windows\\Fonts\\Times.ttf"),"en");
        script_map[EMOJI]              = FT_HB_Font(my_LoadFonts(library, "C:\\Windows\\Fonts\\seguiemj.ttf"),"en");
    
        //////////////////////////////////////////////////////
        // HarfBuzzのUnicode関数の取得
    
        std::u16string text = u"漢字あ゙いう👨‍👨‍👧‍👦àbâáăã";
    
        // 文字列をUTF32で表現した書記素の配列に変換
        std::vector<Grapheme> graphemes;
        u16_to_u32(text.c_str(), graphemes);
    
        Image image(1024, 300);
        // 描画先をクリア
        std::fill(image.image.begin(), image.image.end(), 0);
    
        int draw_offset_x = 0;
        for (size_t i = 0; i < graphemes.size(); i++) {
    
            // 用字を取得
            // ただし絵文字に関しては、HB_SCRIPT_COMMON が入っている
            hb_script_t hbscript = graphemes[i].script;
            FT_HB_Font& face = script_map.at(graphemes[i].is_emoji?EMOJI: hbscript);
    
            draw_offset_x = render_by_font(
                &image               // 出力先
                ,draw_offset_x       // 描画開始位置
                ,face.ftface         // FreeTypeのフォント
                ,graphemes[i].u32str // 描画する文字列
                ,hbscript            // 描画する文字列の用字
                ,hbbuf               // HarfBuzzのバッファ
                ,face.hbfont         // HarfBuzzのフォント
                ,face.lang           // HarfBuzz用の言語
            );
        }
    
        pbmP1_Write("freetypetest_xxx.pbm", image.imageWidth, image.imageHeight, &image.image[0]);
    
    
    }
    

    u16_to_u32.hpp

    #include <unicode/ubrk.h>
    #include <unicode/ustring.h>
    
    #include <vector>
    #include <string>
    
    #include <hb.h>
    #include <hb-ft.h>
    
    #ifdef _DEBUG
    // デバッグ時リンク
    #pragma comment(lib, "icuucd.lib")
    #pragma comment(lib, "icuind.lib")
    #pragma comment(lib,"harfbuzz.lib")
    
    #else
    
    // 要リンク
    #pragma comment(lib, "icuuc.lib")
    #pragma comment(lib, "icuin.lib")
    #pragma comment(lib,"harfbuzz.lib")
    
    #endif
    
    
    // 絵文字判定関数
    bool is_emoji(char32_t c32) {
        bool _emoji = false;
        _emoji |= (bool)u_getIntPropertyValue(c32, UCHAR_EMOJI);
        _emoji |= (bool)u_getIntPropertyValue(c32, UCHAR_EMOJI_PRESENTATION);
        _emoji |= (bool)u_getIntPropertyValue(c32, UCHAR_EMOJI_MODIFIER);
        _emoji |= (bool)u_getIntPropertyValue(c32, UCHAR_EMOJI_MODIFIER_BASE);
        _emoji |= (bool)u_getIntPropertyValue(c32, UCHAR_EMOJI_COMPONENT);
        return _emoji;
    }

    struct Grapheme{
        int32_t start;         // 元のutf16文字列のindex
        int32_t end;           // 元のutf16文字列のindex
        hb_script_t script;    // この書記素(書記素なので複数文字の可能性がある)の先頭の文字の書記素
        std::u32string u32str;  // この書記素のコードポイント表現
        bool is_emoji;         // この書記素が絵文字かどうかを表すフラグ
    };

    //! @brief UTF-16からUTF-32で表現した書記素の配列を作成
    //! @param [in] u16str UTF-16文字列
    //! @param [out] graphemes 書記素の配列
    bool u16_to_u32(
        const char16_t* u16str, 
        std::vector<Grapheme>& graphemes) 
    {
        // hb_unicode_scriptに渡す構造体(解放不要)
        hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_get_default();
    
        UErrorCode status = U_ZERO_ERROR;
    
        // イテレータ作成
        UBreakIterator* bi = ubrk_open(UBRK_CHARACTER, nullptr /*文字単位の処理にロケールは不要*/, nullptr, 0, &status);
    
        if (U_FAILURE(status)) {
            return false;// エラーが発生
        }
    
        int32_t utf16Length = wcslen((wchar_t*)u16str);
        // テキストを設定
        ubrk_setText(bi, (const UChar*)u16str, utf16Length, &status);
    
        if (U_FAILURE(status)) {
            ubrk_close(bi);
            return false;// エラーが発生
        }
    
        // 文字境界を使ってUTF-16からUTF-32に変換
        int32_t start = ubrk_first(bi);
    
        // 文字列(utf16)の最後までループ
        for (int32_t end = ubrk_next(bi); end != UBRK_DONE; start = end, end = ubrk_next(bi)) {
    
            graphemes.push_back(Grapheme{ start, end });
    
            int32_t i = start;
    
            bool is_first = true;
            while(i < end) {
    
                UChar32 c32;
                // ① u16str[i] 以降の文字を一文字コードポイントに変換してcに格納
                // ② iを次の文字の位置に進める
                U16_NEXT(u16str, i, utf16Length, c32);
    
                // コードポイントを保存
                graphemes.back().u32str.push_back(c32);
    
                if(is_first) {
                    is_first = false;
                    graphemes.back().script =
                        hb_unicode_script(ufuncs, c32); // 用字の取得
    
                    graphemes.back().is_emoji = is_emoji(c32);// 絵文字かどうかのチェック
                }
    
            }
    
        }
    
        // 終了処理
        ubrk_close(bi);
    
        return true;
    };
    

    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>
    
    #include <vector>
    #include <string>
    
    
    constexpr int EMOJI = HB_TAG('0', '0', '0', '0');
    
    
    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のフェイス
    int my_FaceDraw(
        Image* image,
        int draw_offset_x,
        hb_buffer_t* hbbuf,
        FT_Face* face
    ) {
    
        //文字数を格納 (書記素数ではない。例えば「あ゙」は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 = draw_offset_x;
    
        // 各文字ごとに描画する
        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);
    
            int cursor_y = 100;
    
    
    
            // 画像書き込み
            // オフセットを加えて座標調整する
            draw(
                image,
                (*face)->glyph->bitmap,
                cursor_x + x_offset + (*face)->glyph->bitmap_left,
                cursor_y + y_offset - (*face)->glyph->bitmap_top
            );
            ///////////////////////////////////////
            ///////////////////////////////////////
            ///////////////////////////////////////
    
            // 次の文字の描画開始値
            cursor_x += x_advance;
            cursor_y += y_advance;
        }
    
        return cursor_x;
    }
    

    //! @brief 指定したフォントで文字列を描画する
    //! @param [out] image          出力先
    //! @param [in]  draw_offset_x  描画開始位置
    //! @param [in]  ft_face        FreeTypeのフォント
    //! @param [in]  text           描画する文字列
    //! @param [in]  script         描画する文字列の用字
    //! @param [in]  hbbuf            HarfBuzzのバッファ
    //! @param [in]  hbfont         HarfBuzzのフォント
    //! @param [in]  lang           HarfBuzz用の言語
    int render_by_font(
        Image* image,
        int draw_offset_x,
        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);
        ////////////////////////
        int next_pos = my_FaceDraw(image, draw_offset_x,hbbuf, ft_face);//FreeType2とHarfBuzzで文字列描画
        ////////////////////////
        return next_pos;
    }
    

    ERROR: Access from your IP address has been blocked for security reasons. Please contact the administrator. が発生

    All In One WP Security & Firewal(AIOS)の機能により管理画面に入れなくなった。基本的には、

    ・一度AIOSを無効にする

    ・ログインする

    ・All In One WP Securityを有効にする

    ・ブロックリストに入っているIPを削除する

    の手順で解決する。

    無効化の方法は、とにかく一度WordPressがAIOSにアクセスができなくなればよいので、フォルダ名を変えるか、アクセス権限を000にする。

    アクセス権限を000に設定

    さくらのレンタルサーバーをつかっているので、コントロールパネルへログインし、ファイルマネージャでアクセス権を設定する。

    ログイン・ブロック解除

    ログインできたら、AIOSのアクセス権を元に戻し、再読み込みをする。

    AIOSが無効になっているので、有効化する。

    Locked IP addressesから、IPアドレスを選択し削除する。

    HarfBuzzでスクリプト(用字)を取得

    ICUライブラリの uscript_getScript を使用すれば用字を取得できる。が、どうやらHarfBuzzのhb_unicode_script関数を使用しても可能らしい。

    #include <iostream>
    #include <vector>
    #include <string>
    
    #include <hb.h>
    #include <hb-ft.h>
    
    #ifdef _DEBUG
    #pragma comment(lib,"harfbuzz.lib")
    #else
    #pragma comment(lib,"harfbuzz.lib")
    #endif
    
    
    #pragma warning(disable:4996)
    
    
    
    // UTF-32の文字列の各文字のスクリプトを取得する関数
    std::vector<hb_script_t> get_scripts_from_utf32(const std::u32string& text, hb_unicode_funcs_t* ufuncs) {
    
        std::vector<hb_script_t> scripts; // 出力用
    
        for (char32_t ch : text) {
    
            hb_script_t script = hb_unicode_script(ufuncs, ch); // スクリプトの取得
    
            scripts.push_back(script);
        }
    
        return scripts;
    }
    
    int main()
    {
        //////////////////////////////////////////////////////
        // HarfBuzzのUnicode関数の取得
    
        hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_get_default(); // hb_unicode_scriptに渡す構造体(解放不要)
    
        std::u32string text = U"漢字あ゙いう👨‍👨‍👧‍👦àbâáăã";
        std::vector<hb_script_t> scripts = get_scripts_from_utf32(text, ufuncs);
    
        ////////////////////////////////////////////
        // テスト コードポイントとスクリプトのペアを作成
        struct cs_pair {
            char32_t c;
            hb_script_t s;
        };
        std::vector<cs_pair> uss;
        for (size_t i = 0; i < text.size(); i++) {
            uss.push_back(cs_pair{ text[i], scripts[i] });
        }
    
        getchar();
    
    }
    

    デバッグモードで確認すると、文字に対応した用字が得られているのがわかる

    icuライブラリでUTF16からUTF32に変換

    icuライブラリのU16_NEXTでコードポイントを取得できる。

    #include <unicode/ubrk.h>
    #include <unicode/ustring.h>
    
    #ifdef _DEBUG
    // デバッグ時リンク
    #pragma comment(lib, "icuucd.lib")
    #pragma comment(lib, "icuind.lib")
    
    #else
    
    // リリース用リンク
    #pragma comment(lib, "icuuc.lib")
    #pragma comment(lib, "icuin.lib")
    
    #endif
    
    
    // Utf16文字列からUtf32文字列に変換
    std::u32string u16_to_u32(const char16_t* u16str) {
    
        UErrorCode status = U_ZERO_ERROR;
    
        // イテレータ作成
        UBreakIterator* bi = ubrk_open(UBRK_CHARACTER, nullptr /*文字単位の処理にロケールは不要*/, nullptr, 0, &status);
    
        if (U_FAILURE(status)) {
            return U"";// エラーが発生
        }
    
        int32_t utf16Length = wcslen((wchar_t*)u16str);
        // テキストを設定
        ubrk_setText(bi, (const UChar*)u16str, utf16Length, &status);
    
        if (U_FAILURE(status)) {
            ubrk_close(bi);
            return U"";// エラーが発生
        }
    
        std::u32string ret32;
    
        // 文字境界を使ってUTF-16からUTF-32に変換
        int32_t start = ubrk_first(bi);
    
        // 文字列(utf16)の最後までループ
        for (int32_t end = ubrk_next(bi); end != UBRK_DONE; start = end, end = ubrk_next(bi)) {
    
            int32_t i = start;
    
            while(i < end) {
    
                UChar32 c32;
                // ① u16str[i] 以降の文字を一文字コードポイントに変換してcに格納
                // ② iを次の文字の位置に進める
                U16_NEXT(u16str, i, utf16Length, c32);
    
                // コードポイントを保存
                ret32.push_back(c32);
    
            }
        }
    
        // 終了処理
        ubrk_close(bi);
    
        return ret32;
    };
    

    テスト

    変換したところで結果を確認するまともな方法(エディタなど)が少ないので、先に作っておいた前回の render_by_font を使い、結果を出力する。

    std::u32stringをFreeType2+HarfBuzzで描画する処理を関数化

    #include"u16_to_u32.hpp"
    
    
    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"
            )
        };
    
        //////////////////////////////////////////////////////
        //////////////////////////////////////////////////////
        //////////////////////////////////////////////////////
    
        {
            std::u32string text32 = u16_to_u32(u"あ゙いう");
            render_by_font(
                &image, 
                faces[0].face, 
                text32.c_str(),
                faces[0].script, 
                hbbuf,
                faces[0].hbfont,
                faces[0].lang.c_str()
            );
    
            pbmP1_Write("freetypetest_jp.pbm", image.imageWidth, image.imageHeight, &image.image[0]);
        }
        {
            std::u32string text32 = u16_to_u32(u"👨‍👨‍👧‍👦");
    
            render_by_font(
                &image, 
                faces[1].face, 
                text32.c_str(),
                faces[1].script,
                hbbuf, 
                faces[1].hbfont,
                faces[1].lang.c_str()
            );
    
            pbmP1_Write("freetypetest_mj.pbm", image.imageWidth, image.imageHeight, &image.image[0]);
        }
        {
            std::u32string text32 = u16_to_u32(u"àbâáăã");
    
            render_by_font(
                &image,
                faces[2].face,
                text32.c_str(),
                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);
    }
    
    
    

    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); }

    結果



    WSL2で動作するアプリケーションのための環境作り

    やりたいこと

    WSL2+Pythonでプログラムを書いた。これをWindows 11上でアイコンをダブルクリックして起動したい。

    Step1. WSL2環境を用意

    基本の環境を汚さないようにするため、Ubuntuをもう一つ入れてそちらで実行できるようにする。

    wsl --install -d Ubuntu-20.04

    ユーザ名、パスワードを入力した後、コンソールをもう一つ開いてwsl -l -v を実行すると、有効な環境一覧が得られる。

    wsl -l -v

    環境が分かったら、 wsl --set-default <環境名> で、使用する環境を切り替える。

    wsl --set-default Ubuntu-20.04

    wsl -d <環境名> で、環境に入れる

    wsl -d Ubuntu-20.04

    Step2. プログラム作成(test.py)

    sudo apt update
    sudo apt install python3 python3-pip python3-tk

    以下のコードをtest.pyとして保存。

    import tkinter as tk
    from tkinter import messagebox
    
    # クリックイベント
    def on_button_click():
        messagebox.showinfo("Message", "HelloWorld")
    
    # メインウィンドウの作成
    root = tk.Tk()
    root.title("MessageBox")
    
    root.geometry("200x100")
    
    # ボタンの作成
    button = tk.Button(root, text="Click Me!", command=on_button_click)
    button.pack(pady=20)
    
    # ウィンドウの表示
    root.mainloop()
    

    実行

    python3 test.py

    Step3. アイコンダブルクリックで実行

    バッチファイルを作成し、以下を記述

    wsl -d Ubuntu-20.04 python3 /path/to/script/test.py

    -d オプションで使用する環境を指定。

    python3 の後は自分のスクリプトが置いてあるパスを指定。

    Ubuntuで弥生の青色申告オンラインを動かせるか試した

    Ubuntu 22.04 LTS +Firefox 129.0.2 で動作確認。ちゃんと動いた。

    Pybind11でC++からPythonモジュールを作成

    Pybind11を使ってみる。

    基本

    my_module_name.pyd

     

    PYBIND11_MODULE(pydファイル名, 変数名 ) {
        変数名 . def (
             "Python側の関数名" ,
             &C++側の関数名
       );
    }

     


    // 呼び出し側のPythonのバージョンのライブラリを使用する
    #pragma comment(lib, "python39.lib")
    #include <pybind11/pybind11.h> namespace py = pybind11; int my_add_func(int a, int b) { return a + b; } // PYBIND11_MODULE(モジュール名, モジュール変数名) // 生成物はmy_module_name.pydという名前にしなければならない PYBIND11_MODULE(my_module_name, m) { m.def( "call_in_python", // Python側で呼び出す関数名 &my_add_func, // C++側の関数名 py::arg("a"), // Python側での引数名(指定省略可) py::arg("b") // Python側での引数名(指定省略可) ); }

    test.py

    import my_module_name
    
    val = my_module_name.call_in_python(10,2)
    
    print(val)
    

    複数の値をタプルで返す

    my_module_name.pyd

    #pragma comment(lib, "python39.lib")
    
    #include <pybind11/pybind11.h>
    
    namespace py = pybind11;
    
    
    std::tuple<int,float> my_calc_func(int a, int b) {
        return
            std::make_tuple(
                a + b,
                (float)(a) / (float)(b)
            );
    }
    
    // PYBIND11_MODULE(モジュール名, モジュール変数名)
    // 生成物はmy_module_name.pydという名前にしなければならない
    PYBIND11_MODULE(my_module_name, m) {
        m.def(
            "call_in_python", // Python側で呼び出す関数名
            &my_calc_func,    // C++側の関数名
            py::arg("a"),      // Python側での引数名(指定省略可)
            py::arg("b")       // Python側での引数名(指定省略可)
        );
    }
    
    

    test.py

    import my_module_name
    
    val1,val2 = my_module_name.call_in_python(10,2)
    
    print(val1)
    print(val2)
    

    クラス,メンバ関数

    #pragma comment(lib, "python39.lib")
    
    
    #include <pybind11/pybind11.h>
    
    namespace py = pybind11; 
    
    
    class MyClass {
    	std::string m_str;
        int value;
    public:
        MyClass(std::string str,int val) : m_str(str),value(val) {}
    
        std::string get() { return m_str + " " + std::to_string(value); }
        void set(std::string str) { m_str = str; }
    };
    
          
    std::string version() {
        return "1.0.0";
    }
    
          
    // PYBIND11_MODULE(モジュール名, モジュール変数名)
    // 生成物はmy_module_name.pydという名前にしなければならない
    PYBIND11_MODULE(my_module_name, m) {
    
        // クラスを追加
        pybind11::class_<MyClass>(m, "MyClassInCPP") // クラス名を指定 PythonからMyClassInCPPとしてアクセス
            .def(pybind11::init<std::string,int>())    // コンストラクタを指定
            .def("get_str", &MyClass::get)            // メンバ関数を追加。Pythonからget_strとしてアクセス
            .def("set_str", &MyClass::set);
    
        // 関数を追加
        m.def("get_version", &version, "get version function");
    }
    

    test.py

    import my_module_name
    
    ss = my_module_name.MyClassInCPP("hello",15)
    
    print("get_str " , ss.get_str() )
    
    ss.set_str("string")
    
    print("get_str " , ss.get_str() )
    
    
    print("version:" , my_module_name.get_version() )
    

    CLionでGithub Copilotを使う

    CLionでGithub Copilotを使用する。

    設定から[プラグイン] → [Marketplace]で Github Copilot を検索。

    サードパーティプラグインに関する通知 が出るが、Github公式のもなので安心して同意する。

    IDEを再起動する。

    再起動後、右下のアイコンをクリックしてLogin to Githubを選択。選択できないなら一度ログアウトする。

    Copy and OpenでGithubへ入って完了。動かないようなら一度CLionを再起動する。

    C++にLuaを組み込む(3)テーブルの値の取得とスタックの状態の確認

    Luaに構造体はないがテーブルがあり構造体と同じような書き方ができる。

    LuaとC++の通信はLuaのスタックを介して行われるため、Luaのスタックの挙動を知っておく必要がある。

    基本的な使い方

    1.lua_getglobalでスクリプト内のテーブルへの参照をスタックへPush

    2.lua_getfieldでテーブルへの参照から指定したキーの値をスタックへPush

    3.lua_tostringでスタックの先頭の値を読み込んで表示

    4.スタックをPopして次の処理に備える

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    // Luaスクリプト
    static const char* script = R"(
    
    MyLuaTable ={
       val_a = "VAL_A",
       val_b = "VAL_B",
       val_c = "VAL_C",
       val_d = "VAL_D",
    }
    
    )";
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // 文字列で与えてスクリプトを実行する
        luaL_dostring(luas, script);
    
        // テーブルへアクセス
        lua_getglobal(luas, "MyLuaTable");// MyLuaTableへの参照をスタックの一番上にPush
    
        {
            // lua_getfieldでテーブルから値を取得
            // 第一引数 ... lua_State
            // 第二引数 ... テーブルのスタック上の位置を現在のスタック位置からの差で表す
            // 第三引数 ... テーブルのキー
            /*
            * スタックの状態
            *  4 □
            *  3 □
            *  2 □ 現在位置==2。   現在位置-1 == 1。従ってlua_getfieldは'1'で参照されているテーブルから'val_a'を取り出し、ここへPushする 
            *  1 ■ MyLuaTableへの参照 lua_getglobalによりPushされている
            */
            lua_getfield(luas, -1, "val_a"); // val_aの値(現在位置からMyLuaTableまでの距離は-1)をスタックの一番上にPush
            const char* value = lua_tostring(luas, -1); // スタックの一番上の値を取得
            printf("value: %s\n", value);
            lua_pop(luas, 1/*要素を一つPOP*/);  // スタックの一番上の要素をPop。これで現在のスタック位置が2に戻る
        }
    

        {
            lua_getfield(luas, -1, "val_b"); // val_bの値(MyLuaTableまでの距離は-1)をスタックの一番上にPush
            const char* value = lua_tostring(luas, -1); // スタックの一番上の値を取得
            printf("value: %s\n", value);
            lua_pop(luas, 1/*要素を一つPOP*/);  // スタックの一番上の要素をPop
        }
    

    // Luaの終了。全てのメモリ解放 lua_close(luas); }
    value: VAL_A
    value: VAL_B

    スタックの状態確認

    lua_getglobalとlua_getfieldの挙動がわからなかったので、スタックの状態を確認する。

    以下のコードはスクリプトで定義されたテーブルへアクセスするために、各値をひたすらスタックへ積んでいく。

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    
    // Luaスクリプト
    static const char* script = R"(
    
    MyLuaTable_1 ={
       val_1_a = "VAL_1_A",
       val_1_b = "VAL_1_B",
       val_1_c = "VAL_1_C",
       val_1_d = "VAL_1_D",
    }
    
    MyLuaTable_2 ={
       val_2_a = "VAL_2_A",
       val_2_b = "VAL_2_B",
       val_2_c = "VAL_2_C",
       val_2_d = "VAL_2_D",
    }
    
    )";
    
    
    // Lua スタックの内容を表示
    void print_stack(lua_State* luas) {
    
        // スタックのトップの位置を取得
        int top = lua_gettop(luas);
    
        // 全てのスタックの内容を表示
        // Luaのスタックは1から始まる
        for (int pos = 1; pos <= top; pos++) {
            
            int type = lua_type(luas, pos);
    
            printf("%d: ", pos);
            switch (type) {
            case LUA_TSTRING:
                printf("'%s'", lua_tostring(luas, pos));
                break;
            case LUA_TBOOLEAN:
                printf(lua_toboolean(luas, pos) ? "true" : "false");
                break;
            case LUA_TNUMBER:
                printf("%g", lua_tonumber(luas, pos));
                break;
            case LUA_TNIL:
                printf("nil");
                break;
            case LUA_TTABLE:
                printf("table Reference");
                break;
            case LUA_TFUNCTION:
                printf("function");
                break;
            case LUA_TUSERDATA:
                printf("userdata");
                break;
            case LUA_TTHREAD:
                printf("thread");
                break;
            case LUA_TLIGHTUSERDATA:
                printf("light userdata");
                break;
            default:
                printf("unknown");
                break;
            }
            printf("\n");
        }
    }
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // 文字列で与えてスクリプトを実行する
        luaL_dostring(luas, script);
    
        {
            // テーブルへアクセス
            lua_getglobal(luas, "MyLuaTable_1");// MyLuaTable_1への参照をスタックの一番上にPush
            lua_getglobal(luas, "MyLuaTable_2");// MyLuaTable_2への参照をスタックの一番上にPush
    
            lua_getfield(luas, -1, "val_2_a"); // val_2_aの値(MyLuaTable_2までの距離は-1)をスタックの一番上にPush
            lua_getfield(luas, -2, "val_2_b"); // val_2_bの値(MyLuaTable_2までの距離は-2)をスタックの一番上にPush
            lua_getfield(luas, -3, "val_2_c"); // val_2_aの値(MyLuaTable_2までの距離は-3)をスタックの一番上にPush
            lua_getfield(luas, -4, "val_2_d"); // val_2_bの値(MyLuaTable_2までの距離は-4)をスタックの一番上にPush
            //        [現在位置-5] にはMyLuaTable_2への参照が積まれている
            lua_getfield(luas, -6, "val_1_a"); // val_1_aの値(MyLuaTable_1までの距離は-6)をスタックの一番上にPush
            lua_getfield(luas, -7, "val_1_b"); // val_1_bの値(MyLuaTable_1までの距離は-7)をスタックの一番上にPush
            lua_getfield(luas, -8, "val_1_c"); // val_1_cの値(MyLuaTable_1までの距離は-8)をスタックの一番上にPush
            lua_getfield(luas, -9, "val_1_d"); // val_1_dの値(MyLuaTable_1までの距離は-9)をスタックの一番上にPush
    
        }
        print_stack(luas); // スタックの内容を表示
    
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    1: table Reference
    2: table Reference
    3: 'VAL_2_A'
    4: 'VAL_2_B'
    5: 'VAL_2_C'
    6: 'VAL_2_D'
    7: 'VAL_1_A'
    8: 'VAL_1_B'
    9: 'VAL_1_C'
    10: 'VAL_1_D'

    スタックの値へアクセス

    lua_tostringの第二引数には、スタックの先頭からの距離を指定する。-1は先頭に積まれている値を指す。例えば-4を指定すれば、先頭から4つ目の値へアクセスする。


        // テーブルへアクセス
        lua_getglobal(luas, "MyLuaTable_1");// MyLuaTable_1への参照をスタックの一番上にPush
        lua_getglobal(luas, "MyLuaTable_2");// MyLuaTable_2への参照をスタックの一番上にPush
    
        lua_getfield(luas, -1, "val_2_a"); // val_2_aの値(MyLuaTable_2までの距離は-1)をスタックの一番上にPush
        lua_getfield(luas, -2, "val_2_b"); // val_2_bの値(MyLuaTable_2までの距離は-2)をスタックの一番上にPush
        lua_getfield(luas, -3, "val_2_c"); // val_2_aの値(MyLuaTable_2までの距離は-3)をスタックの一番上にPush
        lua_getfield(luas, -4, "val_2_d"); // val_2_bの値(MyLuaTable_2までの距離は-4)をスタックの一番上にPush
        //        [現在位置-5] にはMyLuaTable_2への参照が積まれている
        lua_getfield(luas, -6, "val_1_a"); // val_1_aの値(MyLuaTable_1までの距離は-6)をスタックの一番上にPush
        lua_getfield(luas, -7, "val_1_b"); // val_1_bの値(MyLuaTable_1までの距離は-7)をスタックの一番上にPush
        lua_getfield(luas, -8, "val_1_c"); // val_1_cの値(MyLuaTable_1までの距離は-8)をスタックの一番上にPush
        lua_getfield(luas, -9, "val_1_d"); // val_1_dの値(MyLuaTable_1までの距離は-9)をスタックの一番上にPush
    
    ///////////////////////////////////////// // 現在位置から -4 の位置にある値を取得 const char* value = lua_tostring(luas, -4); // val_1_a の値を取得 printf("value: %s\n", value);
    value: VAL_1_A