LoginSignup
4
2

More than 3 years have passed since last update.

続編:putText()関数でtruetype fontを使った *"日本語"* 描画ができるようになります!

Last updated at Posted at 2020-12-20

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;
}

出力結果

image.png

ちょっと補足説明

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を取得できます。

image.png

次の行、はどうやって定義する?

        // 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になります。

以上になります。ご精読、ありがとうございました。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2