スポンサーリンク

FreeType2を試す-5- 一行のテキストを出力

文字列を画像として出力する。

仕組みとしては、画像と高さ、幅情報、移動量情報を全て配列にし、一行分描画してから高さ計算を行う。

#pragma once

#include <ft2build.h>
#include FT_FREETYPE_H

#include <freetype/ftbitmap.h>

#include <vector>

// 人文字の画像とサイズ・位置の情報
struct charpict {
  std::vector<char> m_pic;
  int width;
  int height;
  int left;
  int top;
  int advancex;
  int advancey;
};
// 文字列をラスタライズするクラス
class SingleLineText {
  std::vector<charpict> m_pict;

  int imageWidth; //!< 結果画像の幅
  int imageHeight;//!< 結果画像の高さ
  std::vector<unsigned char> m_image;//!< 結果画像

  FT_Library* m_plib;
  FT_Face face;      // handle to face object
  //! @brief m_imageに書き込むための座標計算関数
  //! @param [in] x 二次元座標のx
  //! @param [in] y 二次元座標のy
  //! @return 一次元配列のindex
  int pixel_pos(const int x, const int y) {
    return y * imageWidth + x;
  }
  //! @brief 作成済みの一文字の画像を全体画像に書き込む
  //! @param [in] index m_pictのindex。何文字目をレンダリングするか
  //! @param [in] pen_x この文字のm_image上の描画開始位置
  //! @param [in] maxtop 全ての文字の中の高さの最大値
  //! @return なし
  void draw_single_character(const int index, const int pen_x, const int maxtop) {

    char* buffer = &m_pict[index].m_pic[0];
    int Width = m_pict[index].width;
    int Height = m_pict[index].height;
    int startx = pen_x + m_pict[index].left;
    int starty = -m_pict[index].top + maxtop;

    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 (xx < 0)continue;
        if (yy < 0)continue;
        if (xx >= imageWidth)continue;
        if (yy >= imageHeight)continue;

        if (buffer[y * Width + x]) {
          m_image[pixel_pos(xx, yy)] = buffer[y * Width + x];
        }
      }
    }

  }
  //! @brief 全ての文字を結果に書き込む
  //! @param [in] maxtop 全ての文字の中の高さの最大値
  //! @return なし
  void characters_to_image(const int maxtop) {

    int pen_x = 0;

    for (size_t i = 0; i < m_pict.size(); i++) {
      if (m_pict[i].m_pic.size()) {
        // 画像書き込み
        draw_single_character(i, pen_x,maxtop);
      }

      // 描画位置を更新
      pen_x += m_pict[i].advancex;
    }

  }
public:
  //! @brief コンストラクタ
  //! @param [in] ftLib FreeTypeライブラリオブジェクトへのポインタ
  //! @param [in] fontfilename フォントファイル名
  SingleLineText(FT_Library* ftLib,const char* fontfilename) {
    m_plib = ftLib;

    FT_Error error;

    // フォントファイル読み込み
    error = FT_New_Face(
      *m_plib,
      fontfilename,
      0,
      &face
    );

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


    if (error == FT_Err_Unknown_File_Format) {
      throw "FT_Err_Unknown_File_Format";
    }
    else if (error) {
      throw "FT_Err";
    }

  }
  //! @brief ラスタライズ
  //! @param [in] text 元のテキスト
  //! @param [in] pixel_size_y 文字サイズ
  //! @return なし
  void rasterize(std::wstring text,const int pixel_size_y) {

    FT_Error error;

    error = FT_Set_Pixel_Sizes(
      face,            // handle to face object
      0,               // pixel_width
      pixel_size_y);   // pixel_height

    int maxtop = INT_MIN;
    imageHeight = INT_MIN;
    imageWidth = 0;

    m_pict.clear();

    //textの各文字について画像を作成
    for (size_t k = 0; k < text.size(); k++) {

      // 文字の取得
      FT_ULong character = text[k];
      FT_UInt char_index = FT_Get_Char_Index(face, character);

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

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

      //データを8bit画像にする
      FT_Bitmap tmpbmp;
      FT_Bitmap_Init(&tmpbmp);
      FT_Bitmap_Convert(*m_plib, &face->glyph->bitmap, &tmpbmp, 1);

      m_pict.emplace_back();

      ////////////////////////////////////////
      //画像を配列に保存
      const int Width = tmpbmp.width;
      const int Height = tmpbmp.rows;
      for (size_t y = 0; y < Height; y++) {
        for (size_t x = 0; x < Width; x++) {

          m_pict.back().m_pic.push_back(tmpbmp.buffer[y * Width + x]);

        }
      }

      FT_Bitmap_Done(*m_plib, &tmpbmp);


      m_pict.back().width = Width;
      m_pict.back().height = Height;
      m_pict.back().left = face->glyph->bitmap_left;
      m_pict.back().top = face->glyph->bitmap_top;
      m_pict.back().advancex = face->glyph->advance.x >> 6;
      m_pict.back().advancey = face->glyph->advance.y >> 6;
      ////////////////////////////////////////

      maxtop = (std::max)(maxtop, m_pict.back().top);

      imageHeight = (std::max)(
        imageHeight, 
        -m_pict[k].top + maxtop + m_pict[k].height
        );
      imageWidth += m_pict.back().advancex;

    }

    //結果画像のメモリ確保
    m_image.resize(imageWidth * imageHeight, 0);

    //画像に全ての文字を書き込む
    characters_to_image(maxtop);

  }
  void done_face() {
    FT_Done_Face(face);
  }
  int ImageWidth() { return imageWidth; }
  int ImageHeight() { return imageHeight; }
  const unsigned char* image()const { return &m_image[0]; }


};

呼び出し

#include <string>
#include <array>

#include "SingleLineText.hpp"

#include "pnm_rw.hpp"

#pragma warning(disable:4996)

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


int main()
{
  FT_Library  library; // handle to library
  FT_Error error;


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

  ////msgothic.ttc
  //meiryo
  SingleLineText slt(&library, "C:\\Windows\\Fonts\\msgothic.ttc");

  int pixel_size_y = 24;

  std::wstring chars = L"いろ は。にほへと,abc d";
  
  slt.rasterize(chars, pixel_size_y);//画像の作成

  //ファイル出力
  write_pnm(
    "C:\\test\\text.pgm", 
    slt.image(),
    slt.ImageWidth(), 
    slt.ImageHeight(), 
    PNM_TYPE::P2
  );


  slt.done_face();
  // FreeType2の解放
  FT_Done_FreeType(library);
}

コメントを残す

メールアドレスが公開されることはありません。

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


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