スポンサーリンク

FreeType2でFT_Get_Kerningでカーニングする

カーニングはアルファベットを描画する際に例えばVとAの間を狭く描画するような描画位置調整のことで、GT_Get_Kerningで文字の位置の差を取得する。

#include <iostream>
#include <vector>

#include <ft2build.h>
#include FT_FREETYPE_H


#pragma warning(disable:4996)

#pragma comment(lib,"freetype.lib")


void pnmP2_Write(
  const char* const fname,
  const int width,
  const int height,
  const unsigned char* const p);

void draw(
  const int width,
  const int height,
  unsigned char* p,
  const int charw,
  const int charh,
  const int ox,
  const int oy,
  const unsigned char* charp
);

int main()
{

  FT_Library  library; // handle to library
  FT_Error error;

  error = FT_Init_FreeType(&library);
  if (error)
    return -1;

  FT_Face face;    // handle to face object

  // フォントファイル読み込み
  error = FT_New_Face(
    library,
    "C:\\Windows\\Fonts\\meiryo.ttc",
    0,
    &face
  );

  //文字コード指定
  error = FT_Select_Charmap(
    face,         // target face object
    FT_ENCODING_UNICODE // エンコード指定
  );


  if (error == FT_Err_Unknown_File_Format)
    return -1;
  else if (error)
    return -1;
   
  
  //この二つの値でフォントサイズ調整
  FT_F26Dot6 fontsize = 32 * 64;
  FT_UInt CHAR_RESOLUTION = 300;
  error = FT_Set_Char_Size(
    face,        // handle to face object
    0,           // char_width in 1/64th of points
    fontsize,      // char_height in 1/64th of points
    CHAR_RESOLUTION,   // horizontal device resolution
    CHAR_RESOLUTION);  // vertical device resolution


  // 出力画像のメモリ確保
  const int iw = 500;
  const int ih = 300;
  std::vector<unsigned char> image(iw*ih,0);

  // カーニングのために直前の文字を保存しておく
  FT_UInt previous_glyph = 0;

// 描画位置 int posx = 0; int posy = 200; for (size_t i = 0; i < 4; i++) { // 文字の取得 FT_ULong character = U"VAOX"[i]; FT_UInt char_index = FT_Get_Char_Index(face, character);
    // カーニング
if(previous_glyph && true/*カーニングしないならfalse*/) { FT_Vector kerning_delta; // 文字のずれ量を保存 // 文字のシフト量を取得 FT_Get_Kerning( face, previous_glyph, char_index, FT_KERNING_DEFAULT, &kerning_delta ); posx += ( kerning_delta.x >> 6 );// 文字のシフト } // 直前に使ったグリフを更新 previous_glyph = char_index;

    // グリフ(字の形状)読込
    error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER);
    if (error)
      return -1; // ignore errors


      // 文字を画像化
    FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);

    // 出力画像に文字を書き込み
    draw(
      //出力先データ
      iw, ih, image.data(),

      // 文字の画像
      face->glyph->bitmap.width,
      face->glyph->bitmap.rows,
      posx + face->glyph->bitmap_left,
      posy - face->glyph->bitmap_top,
      face->glyph->bitmap.buffer
    );

    posx += (face->glyph->advance.x >> 6);
    posy -= (face->glyph->advance.y >> 6);

  }

  pnmP2_Write(// ファイル保存
    "C:\\MyData\\freetypetest.pgm",
    iw,
    ih,
    image.data()
  );

  // FreeType2の解放
  FT_Done_Face(face);
  FT_Done_FreeType(library);
}

//! @brief Portable Gray map
//! @param [in] fname ファイル名
//! @param [in] width 画像の幅
//! @param [in] height 画像の高さ
//! @param [in] p 画像のメモリへのアドレス
//! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む
void pnmP2_Write(
  const char* const fname,
  const int width,
  const int height,
  const unsigned char* const p) { // PPM ASCII

  FILE* fp = fopen(fname, "wb");
  fprintf(fp, "P2\n%d %d\n%d\n", width, height, 255);

  size_t k = 0;
  for (size_t i = 0; i < (size_t)height; i++) {
    for (size_t j = 0; j < (size_t)width; j++) {
      fprintf(fp, "%d ", p[k]);
      k++;
    }
    fprintf(fp, "\n");
  }

  fclose(fp);
}

//! @brief 出力画像へ文字を書き込む
//! @param [in] width 出力先のサイズ
//! @param [in] height 出力先のサイズ
//! @param [out] p 出力先
//! @param [in] charw 文字画像のサイズ
//! @param [in] charh 文字画像のサイズ
//! @param [in] ox 描画始点
//! @param [in] oy 描画始点
//! @param [in] charp 文字画像
void draw(
  const int width,
  const int height,
  unsigned char* p,
  const int charw,
  const int charh,
  const int ox,
  const int oy,
  const unsigned char* charp
) {

  for (int cx = 0; cx < charw; cx++) {
    for (int cy = 0; cy < charh; cy++) {

      int x = ox + cx;
      int y = oy + cy;

      if (x < 0 || x >= width)continue;
      if (y < 0 || y >= height)continue;

      int ipos = y * width + x;
      int cpos = cy * charw + cx;

      int c = (int)(p[ipos]) + (int)(charp[cpos]);

      c = std::min(c, 255);

      p[ipos] = c;

    }
  }

}

コメントを残す

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

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


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