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

#TL;DR 「putText() with STBはもっと頑張れる」
- putText()関数で、日本語表示もできるようになります！
- getTextSize()関数の仕様が微妙に変わるので、お気を付けください！Rectになります。

#はじめに

[putText()関数でtruetype fontを使ったテキスト描画ができるようになりました！](https://qiita.com/hon_no_mushi/items/b139df3dcf6559404b3f) という記事を公開したところ、日本語表示もできるぞ！というコメントをいただいたので、まじめにそこらへんまで頑張ってみました。

# サンプルソースコード

下記サンプルコードは、NotoFontとM-Plusでの描画する例です。

```c
#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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/c25f32d8-0bed-3e7a-0d3d-25e74f5710e0.png)

# ちょっと補足説明

## FontFaceでフォントファイル指定

フォントファイルの指定には、新しく定義されたFontFaceを使います。

```cpp

    // フォントファイルの指定
    // 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()※名前と振る舞いが違うよー

```c++
        // Get the drawing boundary box
        Rect textRect = getTextSize(img.size(),text, textOrg,
                                    fface, fontHeight );
```

「getTextSize()なんだから、文字列のサイズを返す関数」と思いきや、それがちがうと……「getTextRect()」が正しいですね。赤枠のBoundary Boxを取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/50625626-6cf5-f461-4fa5-ff34eeddb6ce.png)

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

```c++
        // Update textOrg
#if 0
        // (1) Same line height
        textOrg += Point( 0, fontHeight );
#else
        // (2)
        textOrg += Point( 0, textRect.height );
#endif
```

次の行の移動方法は、(1)fontHeightに従って、全部同じ高さ分ずつずらす、 (2)赤枠分だけずらす、という２つの方法がある。

基本的には(1)でいいと思うけど、文字を絶対被るリスクはある。

(2)ならば文字が重なることはないけど、空行の高さは消えます（""しかないところのheightは0になる）。


#まとめ（再掲）「putText() with STBはもっと頑張れる」
- putText()関数で、日本語表示もできるようになります！
- getTextSize()関数の仕様が微妙に変わるので、お気を付けください！Rectになります。

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