ぬの部屋(仮)
nu-no-he-ya
  •    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
           
  • Blender 2.8でアドオンを作ってみる

    まず以下のスクリプトをおもむろに実行する

    import bpy
    
    ##############################################
    
    # ボタンを定義
    class ConeButton(bpy.types.Operator):
      bl_idname = "szl.button"
      bl_label = "Add a CONE"
      
      def execute(self, context):
        bpy.ops.mesh.primitive_cone_add()
        return{'FINISHED'}
    
    
    ##############################################
    
    # パネルの項目を定義
    class ConeUI(bpy.types.Panel):
      bl_label = "panel title"
      bl_space_type = "VIEW_3D"
      bl_region_type = "UI"
      bl_category = "AddConePanel"
      
      def draw(self, context):
        self.layout.operator("szl.button")
    
    ##############################################
        
    classes = (
      ConeUI,
      ConeButton
    )
    
    ##############################################
    
    # アドオン有効化時に呼び出される
    def register():
      for c in classes:
        bpy.utils.register_class(c)
    
    # アドオン無効化時に呼び出される
    def unregister():
      for c in classes:
        bpy.utils.unregister_class(c)
    
    
    if __name__ == "__main__": register()
     

    すると、パネルに新しい項目が追加され、ボタンを押すとConeが生成される。

    これは上記スクリプトの最後の register() 関数が実行されたため。

    しかしBlenderを再起動すれば消えてしまう。そこでまず以下のように変更を加える。ファイル名は add-cone-addon.py とでもしておく。

    下記、bl_infoの部分があるとアドオンとして認識される。

    また、registerはBlenderがアドオンを読み込んだときに自動で呼び出されるので、一番下の呼び出し部分を削除する。

    import bpy
    
    ##############################################
    
    bl_info = { "name" : "sample: add-on-name", "author" : "yodori soratori", "version" : (1, 0), "blender" : (2, 81, 0), "location" : "location", "description": "sample", "warning" : "warning message", # 空だと!アイコンが出ない "support" : "TESTING", # または OFFICIAL または COMMUNITY "wiki_url" : "", "tracker_url": "", "category" : "Object" #アドオンのカテゴリ }
    ############################################## # ボタンを定義 class ConeButton(bpy.types.Operator): bl_idname = "szl.button" bl_label = "Add a CONE" def execute(self, context): bpy.ops.mesh.primitive_cone_add() return{'FINISHED'} ############################################## # class ConeUI(bpy.types.Panel): bl_label = "panel title" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "AddConePanel" def draw(self, context): self.layout.operator("szl.button") ############################################## classes = ( ConeUI, ConeButton ) ############################################## # アドオン有効化時に呼び出される def register(): for c in classes: bpy.utils.register_class(c) # アドオン無効化時に呼び出される def unregister(): for c in classes: bpy.utils.unregister_class(c)
    #if __name__ == "__main__": # register()

    そして、Preference → Add-ons でアドオンとしてインストールする

    参考

    https://dskjal.com/blender/ui-script.html

    Blenderで二本のエッジの交点に点を追加する(Python) 2.79,2.8両対応

    エッジを二本選択し、その交点を求めたい。


    How can I add vertices to intersection of two edges?

    https://blender.stackexchange.com/questions/2976/how-can-i-add-vertices-to-intersection-of-two-edges

    のPythonスクリプトを実行すると、二辺の交差点に頂点を一つ追加できる。(Blender 2.79 , 2.8 両対応)

    しかし頂点が一つ置かれるだけだと不便なので、各エッジをsubdivideする形で追加するように変更した。

    コードは以下:

    import bmesh
    import bpy
    from mathutils import geometry
    
    # get cross point of 2 edges
    def calc_cross_coordinate(edge2):
    
    
        if len(edge2) == 2:
            [[v1, v2], [v3, v4]] = [[v.co for v in e.verts] for e in edge2]
    
            iv = geometry.intersect_line_line(v1, v2, v3, v4)
            iv = (iv[0] + iv[1]) / 2
            return iv
        
    # subdivide 2 edges and move the points to cross point
    def subdivide_selects(edge2, moveto):
        obj = bpy.context.object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)
    
        ret = bmesh.ops.subdivide_edges(bm,
            edges=edge2,
            use_grid_fill=True,
            cuts=1)
        bmesh.update_edit_mesh(me)
    
        for i in ret['geom_split']:
            if type(i) == bmesh.types.BMVert:
                i.co=moveto
    
    def cross_subdivide():
        obj = bpy.context.object
        me = obj.data
        bm = bmesh.from_edit_mesh(me)
    
        edge2 = [e for e in bm.edges if e.select]
        if len(edge2) == 2:
            pos = calc_cross_coordinate(edge2)
            subdivide_selects(edge2,pos)
        
    cross_subdivide()
        
    

    実行例

    解説

    cross_subdivide

    今回の処理を行う関数。

    エッジが二本選択されているとき、二本のエッジをsubdivideし、新規頂点を交点に作成する。

    calc_cross_coordinate

    二本のエッジを引数にとり、geometry.intersect_line_lineで交差している座標を求める。

    三次元の線分の場合、現実には誤差の関係で絶対に交差しないので、交点は二つ求まる。その中間点を交点(iv)としている。

    subdivide_selects

    bmesh.ops.subdivide_edgesでオブジェクトをsubdivideしている。

    戻り値の[‘geom_split’]に作成されたデータが入っているので、データ型がBMVertのものだけを取り出し、座標を交点で上書きする

    OpenGLで文字列描画(Asciiのみ)

    glutBitmapCharacterは珍しい関数では無いけれどなぜかどのサンプルもzを殺している。個人的には以下のようにx,y,zの指定をちゃんとやった方が圧倒的に使いやすい。

    //! @brief 文字列を表示
    //! @param [in] x 三次元の座標(X)
    //! @param [in] y 三次元の座標(Y)
    //! @param [in] z 三次元の座標(Z)
    //! @param [in] str 文字列(英語のみ)
    void render_string(float x, float y, float z, const char* str) {
      glRasterPos3f(x, y, z);
    
      const char* c = str;
      while (*c) {
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c++);
      }
    }
    

    単に現在の状態を表示するだけならコンソールでいいし、見栄えが重要ならそもそもglutなんて使わないし、何より、文字を左上に出すならちゃんとglLoadIdentityしてから世界座標系で指定する必要がある。手間を省けてない。

    //! @brief 文字列を表示
    //! @param [in] x 三次元の座標(X)
    //! @param [in] y 三次元の座標(Y)
    //! @param [in] z 三次元の座標(Z)
    //! @param [in] str 文字列(英語のみ)
    void render_string(float x, float y, float z, const char* str) {
      glRasterPos3f(x, y, z);
    
      const char* c = str;
      while (*c) {
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c++);
      }
    }
    
    
    int width, height;
    //回転オブジェクト定義
    nu::mrotate camr;
    
    //表示
    void disp(void) {
      glClear(GL_COLOR_BUFFER_BIT);
      glViewport(0, 0, width, height);
    
      glPushMatrix();
    
      //原点を視線方向に0.5ずらす
      glTranslated(0, 0, -0.5);
    
      //回転行列を適用
      double mat[16];
      glMultMatrixd(camr.getmatrix(mat));
    
      //一辺0.7のキューブを描画
      cube(0.7);
    
    
      glColor3d(1, 1, 1);
    
      double ws = -0.7 / 2;
      double we = 0.7 / 2;
      render_string(ws, ws, ws, "min");
      render_string(we, we, we, "max");
    
      glPopMatrix();
    
      glLoadIdentity();
      render_string(-1, 0.9, 0, "sample");
    
      glFlush();
    }
    

    (今更)FirefoxのトップサイトのGoogleとAmazonを開けるようにする(@付き)

    ずっと不便き極まりなかったことが今更だがわかったのでここに残しておきたい。というか、世の人は多分今の方が使いやすいか、簡単に戻し型がわかってしまうのだろう。だから私の使う検索ワードではヒットしないのである。

    問題

    ある日の更新を境に、Firefoxホームに表示されたgoogleやamazonをクリックすると検索になってしまい、サイトに飛ばなくなった。

    記憶が確かなら元々はよくアクセスするサイトが自動で出てきていたのに、虫眼鏡マークのボタンに上書きされてしまった格好だったと思う。

    虫眼鏡のマークがついているやつをクリックすると
    サイトに飛ばずに検索ワード入力になる

    @がついていると検索ワード入力になるのかとか思って色々試したが戻らなかった。

    解決方法

    @amazonと@googleは検索エンジン扱いになっている。つまりリンクでは無い。だからトップサイトとして登録し、それとは全く別に、(必要であれば)検索エンジンとしてのアイコンを無効にする。

    トップサイトとして登録

    トップサイト右側の…から「トップサイト追加」
    amazonのURIを入力し「追加」

    検索エンジンを非表示にする

    トップサイト右側の…から「検索エンジンを追加」
    チェックを外す
    検索エンジンとしてのamazonが消える

    Bitnami MODx Stackを動かしてみる(3) ページを作る

    bitnamiのバナーについて

    ロゴを消す方法

    sudo /opt/bitnami/apps/modx/bnconfig –disable_banner 1

    としたのち、以下でapacheを再起動

    sudo /opt/bitnami/ctlscript.sh restart apache

    もう一度表示する方法

    以下でいいはずなのだが、

    sudo /opt/bitnami/apps/modx/bnconfig –disable_banner 0

    なぜか動いてくれないので、以下を実行する

    sudo rm -rf /opt/bitnami/apps/bitnami/banner/disable-banner

    ページを作成

    「ドキュメント」の左上の「新しいドキュメント」をクリック

    「コンテンツ」に本文を書いて「保存」をクリック。「プレビュー」で表示を確認できる。

    HTMLタグを直に打てる

    トップページの変更

    サイトのトップページの設定がデフォルトではHomeになっているので、システム設定で site_start の項目を検索し、トップページにしたい記事のIDを設定する

    Bitnami MODx Stackを動かしてみる(2)テンプレートを作ってみる

    テンプレートの作成

    エレメント→テンプレートを右クリックし、「テンプレートを作成」を選択

    画面を下の方にスクロールするとテンプレートの入力欄がある

    テンプレートを入力し、「保存」をクリックする

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF8" />
      <title> [[*pagetitle]] | [[++site_name]]</title>
    </head>
    <body>
        <font color="blue">[[++site_url]]</font><br />
        <font color="green">[[*longtitle:default=`[[*pagetitle]]`]]</font><br />
        <font color="red">  [[*content]] </font><br />
    </body>
    </html>
    

    テンプレートの適用

    「ドキュメント」からテンプレートを適用したいページをクリックし、「使用テンプレート」で作成したテンプレートを選択し、「保存」をクリック

    保存後、「プレビュー」で結果を表示する

    変数に関する資料

    リソース変数やコンフィグ変数の指定方法が、バージョンの差なのかタイプの差なのか知らないが日本公式のものでは動かなかったので、以下を参考にする

    https://docs.modx.com/current/en/building-sites/tag-syntax/common

    Bitnami MODx Stackを動かしてみる(1) 仮想マシンの設定

    概要

    Bitnami MODx StackはCMSのMODxを使える状態で配布されている仮想マシンのイメージ。

    Step.1 以下から仮想マシンをダウンロードする

    MODX Virtual Machines

    https://bitnami.com/stack/modx/virtual-machine

    ※現時点でのファイル名 bitnami-modx-2.7.2pl-2-linux-debian-9-x86_64.ova

    Step.2 VirtualBoxを起動し、.ovaをインポート

    Step.3 仮想マシンを起動し、ログイン名 bitnami , パスワード bitnami でdebianにログイン

    ※この時上記ログインパスワードを強制的に変えさせられるかもしれないのでなにか適当に入力する

    Step.4 ホストOSからMODxにログインする

    ID/パスワードはdebianの起動時に出てくるが、

    cat ./bitnami_credentials

    としても確認できる

    URLはIPアドレスをipconfigから確認できる。

    例 http://192.168.1.3

    Step.5 一応日本語化する

    もう少し詳細な説明

    Step.1 以下から仮想マシンをダウンロードする

    MODX Virtual Machines

    https://bitnami.com/stack/modx/virtual-machine

    Step.2 VirtualBoxを起動し、.ovaをインポート

    Step.3 仮想マシンを起動し、debianにログイン

    起動直後のログイン画面に

    • サイトURL
    • MODxへのログイン情報
    • debianへのログイン情報

    が表示されいてる

    bitnami / bitnami でログインする

    この画面が出てこない場合、ログイン情報は、以下のコマンドで確認できる

    cat ./bitnami_credentials

    サイトURLはipconfigで確認する

    sudo ifconfig

    Step.4 ホストOSからMODxにログインする

    サイトURL
    http://IPADDRESS/
     
    ログインURL
    http://IPADDRESS/manager/

    パスワードは上記の
    U6PfP5tB1Mqn等

    Step.5 一応日本語化する

    System Settingsを開く

    「Filter by area…」にlanguageと入力し設定項目を絞り込む

    Manager Language の項目を ja に設定

    設定を変えてもなぜか暫く変わらないので注意。あちこち移動しているといつの間にか変わる

    なお日本語での言語の設定名は「管理画面の言語」

    その他

    続く…

    参考

    Find application credentials
    https://docs.bitnami.com/bch/faq/get-started/find-credentials/

    MODX Virtual Machines
    https://bitnami.com/stack/modx/virtual-machine

    Obtain application and server credentials
    https://docs.bitnami.com/virtual-machine/apps/modx/get-started/first-steps/

    stbライブラリでtruetypeフォントをラスタライズ(2)

    まず、前回とほぼ同じプログラムで、下記( ※ )部分を「、」などの文字に変更する。

    //参考
    //https://gist.github.com/cloudwu/766bccc60c254f9cc2abfa397bcff2ea
    
    #include<windows.h>
    #include <tchar.h>
    
    #include <cstdio>
    
    #define STB_TRUETYPE_IMPLEMENTATION
    #define STBTT_STATIC
    
    #include "stb_truetype.h"
    
    // utf8文字コードをコードポイントに変換
    unsigned int utf8_decode(const char* o);
    
    // フォントで文字を描画した画像を作成
    void drawfontchar(unsigned int f);
    
    unsigned char* pixels = nullptr; //画素の格納先
    int iwidth; //画像サイズの格納先
    int iheight;
    
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      HDC hdc;
      PAINTSTRUCT ps;
      switch (msg) {
      case WM_DESTROY:
        //画像の破棄
        delete[] pixels;
    
    
        PostQuitMessage(0);
        return 0;
      case WM_PAINT://画面に表示
        hdc = BeginPaint(hwnd, &ps);
        if (pixels != nullptr) {
          RECT rect;
          GetClientRect(hwnd, &rect);
          FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
    
          for (int y = 0; y < iheight; y++) {
            for (int x = 0; x < iwidth; x++) {
              unsigned char r = pixels[y * iwidth + x];
              if (r == 0)
                SetPixel(hdc, x, y, RGB(255, 0, 0));
              else
                SetPixel(hdc, x, y, RGB(0, 0, 0));
            }
          }
        }
    
    
        EndPaint(hwnd, &ps);
        break;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      PSTR lpCmdLine, int nCmdShow) {
      HWND hwnd;
      WNDCLASS winc;
      MSG msg;
    
      winc.style = CS_HREDRAW | CS_VREDRAW;
      winc.lpfnWndProc = WndProc;
      winc.cbClsExtra = winc.cbWndExtra = 0;
      winc.hInstance = hInstance;
      winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      winc.hCursor = LoadCursor(NULL, IDC_ARROW);
      winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      winc.lpszMenuName = NULL;
      winc.lpszClassName = TEXT("NEW_WINDOW");
    
      if (!RegisterClass(&winc)) return 0;
    
    
    //指定した文字のunicodeのコードポイントを取得(※) unsigned int c = utf8_decode(u8"ぬ");
    //一文字書かれた画像を作成(pixelsに格納) drawfontchar(c); hwnd = CreateWindow( TEXT("NEW_WINDOW"), TEXT("example : stb_truetype.h"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 150, 150, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return 0; while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); return msg.wParam; } unsigned char ttf_buffer[1 << 25]; //一文字書かれた画像を作成 void drawfontchar(unsigned int codepoint) { const int HEIGHT = 100; stbtt_fontinfo font; //フォントファイルを開く FILE* pf_font = fopen(R"(C:\Windows\Fonts\msgothic.ttc)", "rb"); fread(ttf_buffer, 1, 1 << 25, pf_font); fclose(pf_font); stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0)); float scale = stbtt_ScaleForPixelHeight(&font, HEIGHT); int ascent, baseline, decent; stbtt_GetFontVMetrics(&font, &ascent, &decent, 0); baseline = (int)(ascent * scale); int height = (int)((ascent - decent) * scale); int x0, y0, x1, y1; stbtt_GetCodepointBitmapBox(&font, codepoint, scale, scale, &x0, &y0, &x1, &y1); //出力先のメモリ確保 iwidth = x1 - x0; iheight = y1 - y0; pixels = new unsigned char[iheight * iwidth]; stbtt_MakeCodepointBitmap( &font, //フォント情報 pixels, //描画先 iwidth, //描画先の幅 iheight,//描画先の高さ iwidth, //描画先の画像の一行のバイト数(?) scale, //X方向倍率 scale, //Y方向倍率 codepoint); } //utf8一文字をコードポイントに変換 unsigned int utf8_decode(const char* o) { const unsigned int MAXUNICODE = 0x10FFFF; static const unsigned int limits[] = { 0xFF, 0x7F, 0x7FF, 0xFFFF }; const unsigned char* s = (const unsigned char*)o; unsigned int c = s[0]; unsigned int res = 0; /* final result */ if (c < 0x80) /* ascii? */ res = c; else { int count = 0; /* to count number of continuation bytes */ while (c & 0x40) { /* still have continuation bytes? */ int cc = s[++count]; /* read next byte */ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ return -1; /* invalid byte sequence */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ c <<= 1; /* to test next bit */ } res |= ((c & 0x7F) << (count * 5)); /* add first byte */ if (count > 3 || res > MAXUNICODE || res <= limits[count]) return -1; /* invalid byte sequence */ s += count; /* skip continuation bytes read */ } return res; }
    「ぬ」
    「、」

    出力されるのは文字の部分だけなので、そのまま画像の幅で並べると以下のようになる。

    高さの調節

    まず、グローバル変数に以下を追加する

    int _Baseline_;
    int _Y0;
    

    次に、drawfontchar関数に以下を追加する

    //一文字書かれた画像を作成
    void drawfontchar(unsigned int codepoint) {
    
      const int HEIGHT = 100;
    
      stbtt_fontinfo font;
    
      //フォントファイルを開く
      FILE* pf_font = fopen(R"(C:\Windows\Fonts\msgothic.ttc)", "rb");
      fread(ttf_buffer, 1, 1 << 25, pf_font);
      fclose(pf_font);
    
      stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
      float scale = stbtt_ScaleForPixelHeight(&font, HEIGHT);
      int ascent, baseline, decent;
      stbtt_GetFontVMetrics(&font, &ascent, &decent, 0);
      baseline = (int)(ascent * scale);
      int height = (int)((ascent - decent) * scale);
    
      int x0, y0, x1, y1;
      stbtt_GetCodepointBitmapBox(&font, codepoint, scale, scale, &x0, &y0, &x1, &y1);
    
    
    _Baseline_ = baseline; _Y0 = y0;
    //出力先のメモリ確保 iwidth = x1 - x0; iheight = y1 - y0; pixels = new unsigned char[iheight * iwidth]; stbtt_MakeCodepointBitmap( &font, //フォント情報 pixels, //描画先 iwidth, //描画先の幅 iheight,//描画先の高さ iwidth, //描画先の画像の一行のバイト数(?) scale, //X方向倍率 scale, //Y方向倍率 codepoint); }

    さらに、表示時にY方向にオフセットを加える

    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
      HDC hdc;
      PAINTSTRUCT ps;
      switch (msg) {
      case WM_DESTROY:
        //画像の破棄
        delete[] pixels;
    
    
        PostQuitMessage(0);
        return 0;
      case WM_PAINT://画面に表示
        hdc = BeginPaint(hwnd, &ps);
        if (pixels != nullptr) {
          RECT rect;
          GetClientRect(hwnd, &rect);
          FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
    
          for (int y = 0; y < iheight; y++) {
            for (int x = 0; x < iwidth; x++) {
              unsigned char r = pixels[y * iwidth + x];
              if (r == 0)
                SetPixel(hdc, x, y + _Y0 + _Baseline_, RGB(255, 0, 0));
              else
                SetPixel(hdc, x, y + _Y0 + _Baseline_, RGB(0, 0, 0));
            }
          }
        }
    
    
        EndPaint(hwnd, &ps);
        break;
      }
      return DefWindowProc(hwnd, msg, wp, lp);
    }
    

    各文字ごとに、y0とbaselineで高さの調整を行った場合。

    幅の調整

    さらに、文字ごとに一定の間隔で並べると

    幅に関しては揃える基準が無いのでX方向のオフセットは定数にする。

    stbライブラリでtruetypeフォントをラスタライズ(1)

    件のstbライブラリにあるstb_truetype.hでttfのラスタライズができる。public domainでttfが簡単に使えるなら試してみたい。

    サンプル

    //参考
    //https://gist.github.com/cloudwu/766bccc60c254f9cc2abfa397bcff2ea
    
    #include<windows.h>
    #include <tchar.h>
    
    #include <cstdio>
    
    #define STB_TRUETYPE_IMPLEMENTATION
    #define STBTT_STATIC
    
    #include "stb_truetype.h"
    
    // utf8文字コードをコードポイントに変換
    unsigned int utf8_decode(const char* o);
    
    // フォントで文字を描画した画像を作成
    void drawfontchar(unsigned int f);
    
    
    unsigned char* pixels = nullptr; //画素の格納先 int iwidth; //画像サイズの格納先 int iheight;
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_DESTROY:
    //画像の破棄 delete [] pixels;
    PostQuitMessage(0); return 0; case WM_PAINT://画面に表示 hdc = BeginPaint(hwnd, &ps);
    if (pixels != nullptr) { for (int y = 0; y < iheight; y++) { for (int x = 0; x < iwidth; x++) { unsigned char r = pixels[y * iwidth + x]; if (r == 0) SetPixel(hdc, x, y, RGB(255, 255, 255)); else SetPixel(hdc, x, y, RGB(0, 0, 0)); } } }
    EndPaint(hwnd, &ps); break; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { HWND hwnd; WNDCLASS winc; MSG msg; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("NEW_WINDOW"); if (!RegisterClass(&winc)) return 0;
    //指定した文字のunicodeのコードポイントを取得 unsigned int c = utf8_decode(u8"ぬ"); //一文字書かれた画像を作成(pixelsに格納) drawfontchar(c);
    hwnd = CreateWindow( TEXT("NEW_WINDOW"), TEXT("example : stb_truetype.h"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 200, 100, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return 0; while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); return msg.wParam; } unsigned char ttf_buffer[1 << 25];
    //一文字書かれた画像を作成 void drawfontchar(unsigned int codepoint) { const int HEIGHT = 60; stbtt_fontinfo font; //フォントファイルを開く FILE* pf_font = fopen(R"(C:\fonts\GenShinGothic-Bold.ttf)", "rb"); fread(ttf_buffer, 1, 1 << 25, pf_font); stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0)); float scale = stbtt_ScaleForPixelHeight(&font, HEIGHT); int ascent, baseline, decent; stbtt_GetFontVMetrics(&font, &ascent, &decent, 0); baseline = (int)(ascent * scale); int height = (int)((ascent - decent) * scale); int x0, y0, x1, y1; stbtt_GetCodepointBitmapBox(&font, codepoint, scale, scale, &x0, &y0, &x1, &y1); //出力先のメモリ確保 iwidth = x1 - x0; iheight = y1 - y0; pixels = new unsigned char[iheight * iwidth]; stbtt_MakeCodepointBitmap( &font, //フォント情報 pixels, //描画先 iwidth, //描画先の幅 iheight,//描画先の高さ iwidth, //描画先の画像の一行のバイト数(?) scale, //X方向倍率 scale, //Y方向倍率 codepoint); }
    //utf8一文字をコードポイントに変換
    
    unsigned int utf8_decode(const char* o) { const unsigned int MAXUNICODE = 0x10FFFF; static const unsigned int limits[] = { 0xFF, 0x7F, 0x7FF, 0xFFFF }; const unsigned char* s = (const unsigned char*)o; unsigned int c = s[0]; unsigned int res = 0; /* final result */ if (c < 0x80) /* ascii? */ res = c; else { int count = 0; /* to count number of continuation bytes */ while (c & 0x40) { /* still have continuation bytes? */ int cc = s[++count]; /* read next byte */ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ return -1; /* invalid byte sequence */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ c <<= 1; /* to test next bit */ } res |= ((c & 0x7F) << (count * 5)); /* add first byte */ if (count > 3 || res > MAXUNICODE || res <= limits[count]) return -1; /* invalid byte sequence */ s += count; /* skip continuation bytes read */ } return res; }

    実行結果

    参考

    元のプログラム

    以下のサンプルコードに手を加え、win32apiで文字を一つ表示できるようにした。

    https://gist.github.com/cloudwu/766bccc60c254f9cc2abfa397bcff2ea

    使用フォント

    源真ゴシック

    http://jikasei.me/font/genshin

    stbライブラリで画像読み込み

    サンプルコード

    #include<windows.h>
    #include <tchar.h>
    
    #define STB_IMAGE_IMPLEMENTATION
    #include "stb_image.h"
    
    
    unsigned char* pixels = nullptr; //画素の格納先 int width; //画像サイズの格納先 int height; int bpp; //一画素のバイト数
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_DESTROY:
    //画像の破棄 stbi_image_free(pixels);
    PostQuitMessage(0); return 0; case WM_PAINT://画面に表示 hdc = BeginPaint(hwnd, &ps);
    if (pixels != nullptr){ for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { unsigned char r = pixels[(y*width + x)*bpp + 0]; unsigned char g = pixels[(y*width + x)*bpp + 1]; unsigned char b = pixels[(y*width + x)*bpp + 2]; SetPixel(hdc,x, y, RGB(r, g, b)); } }
    }
    EndPaint(hwnd, &ps); break; } return DefWindowProc(hwnd, msg, wp, lp); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { HWND hwnd; WNDCLASS winc; MSG msg; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = WndProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("NEW_WINDOW"); if (!RegisterClass(&winc)) return 0; hwnd = CreateWindow( TEXT("NEW_WINDOW"), TEXT("example : stb_image.h"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return 0;
    //画像のロード pixels = stbi_load(R"(C:\mydata\test\beach-blur-clouds-dawn-462030.jpg)", &width, &height, &bpp, 0);
    //https://odashi.hatenablog.com/entry/20110911/1315730376 RECT rw, rc; ::GetWindowRect(hwnd, &rw); // ウィンドウ全体のサイズ ::GetClientRect(hwnd, &rc); // クライアント領域のサイズ // 希望するクライアント領域のサイズを持つウィンドウサイズを計算 int new_width = (rw.right - rw.left) - (rc.right - rc.left) + width; int new_height = (rw.bottom - rw.top) - (rc.bottom - rc.top) + height; SetWindowPos(hwnd, NULL, 0, 0, new_width, new_height, SWP_NOMOVE | SWP_NOZORDER);
    while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg); return msg.wParam; }

    実行結果

    参考

    画像

    pexels

    https://www.pexels.com/ja-jp/photo/hdr-462030/

    クライアント領域のサイズからウィンドウ全体のサイズを設定する

    更新しない備忘録改二

    https://odashi.hatenablog.com/entry/20110911/1315730376
    

    stbi_image使用法参考

    でらうま倶楽部

    http://blog.livedoor.jp/tek_nishi/archives/9265518.html