文字列を画像として出力する。
仕組みとしては、画像と高さ、幅情報、移動量情報を全て配列にし、一行分描画してから高さ計算を行う。
#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); }