スポンサーリンク

| キーワード:

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方向のオフセットは定数にする。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: