#TL;DR 「putText() with STBはもっと頑張れる」
- putText()関数で、日本語表示もできるようになります!
- getTextSize()関数の仕様が微妙に変わるので、お気を付けください!Rectになります。
#はじめに
putText()関数でtruetype fontを使ったテキスト描画ができるようになりました! という記事を公開したところ、日本語表示もできるぞ!というコメントをいただいたので、まじめにそこらへんまで頑張ってみました。
サンプルソースコード
下記サンプルコードは、NotoFontとM-Plusでの描画する例です。
#include <opencv2/imgproc.hpp> // cv::FONT*, cv::LINE*, cv::FILLED
#include <opencv2/highgui.hpp> // imwrite
#include <iostream>
using namespace cv;
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cerr << "Filename required" << std::endl;
return 1;
}
Mat img(600, 800, CV_8UC3, Scalar::all(0));
// フォントファイルの指定
// ttf/otfそのものを指定する以外に、gz圧縮したのを指定もできる
// postfix".gz"は必須になります
FontFace fface("./mplus-1p-medium.otf.gz");
// FontFace fface("/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf");
int fontHeight = 40;
Point textOrg( 50, 200 ) ;
String textList[] = {
u8"こんにちは、STB putText()さん",
u8"",
u8"Funny Text inside the box",
u8"",
u8"iiiiiiiiiiiiiiiii",
u8"WWWWWWWWWWWWWWWWW",
u8"",
u8"_qgjyp - under baseline",
u8"qgjyp - under baseline",
};
for ( const auto& text : textList ) {
// Get the drawing boundary box
Rect textRect = getTextSize(img.size(),text, textOrg,
fface, fontHeight );
// draw the box
rectangle(img, textRect, Scalar(0,0,255) );
// ... and the baseline first
line(img,
textOrg + Point(0, 0),
textOrg + Point(textRect.width, 0),
Scalar(0, 255, 255));
// then put the text itself
putText(img,
text,
textOrg,
Scalar::all(255),
fface,
fontHeight);
// Update textOrg
#if 0
// (1) Same line height
textOrg += Point( 0, fontHeight );
#else
// (2)
textOrg += Point( 0, textRect.height );
#endif
}
cv::imwrite(argv[1], img);
return 0;
}
出力結果
ちょっと補足説明
FontFaceでフォントファイル指定
フォントファイルの指定には、新しく定義されたFontFaceを使います。
// フォントファイルの指定
// ttf/otfそのものを指定する以外に、gz圧縮したのを指定もできる
// postfix".gz"は必須になります
FontFace fface("./mplus-1p-medium.otf.gz");
// FontFace fface("/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf");
このように、普通のttfファイル以外に、gz圧縮したファイルを突っ込むこともできるし、otfを突っ込むこともできます。
getTextSize()※名前と振る舞いが違うよー
// Get the drawing boundary box
Rect textRect = getTextSize(img.size(),text, textOrg,
fface, fontHeight );
「getTextSize()なんだから、文字列のサイズを返す関数」と思いきや、それがちがうと……「getTextRect()」が正しいですね。赤枠のBoundary Boxを取得できます。
次の行、はどうやって定義する?
// Update textOrg
#if 0
// (1) Same line height
textOrg += Point( 0, fontHeight );
#else
// (2)
textOrg += Point( 0, textRect.height );
#endif
次の行の移動方法は、(1)fontHeightに従って、全部同じ高さ分ずつずらす、 (2)赤枠分だけずらす、という2つの方法がある。
基本的には(1)でいいと思うけど、文字を絶対被るリスクはある。
(2)ならば文字が重なることはないけど、空行の高さは消えます(""しかないところのheightは0になる)。
#まとめ(再掲)「putText() with STBはもっと頑張れる」
- putText()関数で、日本語表示もできるようになります!
- getTextSize()関数の仕様が微妙に変わるので、お気を付けください!Rectになります。
以上になります。ご精読、ありがとうございました。