Qtで文字と画像の混在テキストを描画する


最近作った便利ライブラリの紹介です。

テキストを描画するには、QPainter::drawText関数を使用しますが、テキストと同時に画像(アイコンなど)を一緒に描画したいことがよくあります。QLabelQPushButtonは画像とテキストを表示する機能を持っていますが、自前でQPainter::drawText関数を使ってテキストを描画する必要があって、ついでに画像も一緒に描画したいとき、さらに言うと、記号や絵文字フォントではなく、アプリケーション内に格納されているリソースの画像をテキストと一緒に描画したいことがあります。

画像

GUIフレームワークライブラリであるQtは画像を扱う機能が豊富です。用途に応じて、ピックスマップ、イメージ、アイコンがあります。

QPixmap pm(":/image/sushi.svg");

描画に最適化された画像はQPixmapです。多少語弊がありますが、Windowsで言うところのDDB(デバイス依存ビットマップ)に近いものと言えるかもしれません。

QImage img(":/image/sushi.svg");

ピクセル指向の画像はQImageです。scanLine関数でピクセルのポインタを取得して、画像を直接書き換える様な用途ではこれを使います。Windowsで例えれば、DIB(デバイス独立ビットマップ)に相当します。

QIcon icon(":/image/sushi.svg");

画像サイズや縦横比を良い感じにしてくれる画像はQIconです。WindowsのHICONより取り扱いが簡単です。

どれを使うにしても、多くの場合相互に変換できますので、あまり気にしなくていいでしょう。通常は、画像を描画したいだけならQPixmapQIcon、画像処理でピクセル操作するならQImageを使うと覚えておけばいいです。

描画するには、QPainter::drawPixmapQPainter::drawImageQIcon::paintのいずれかの関数を使います。

今回はQIconを利用します。

画像ファイルの形式は何でも構いませんが、拡大縮小された場合にも綺麗に描画できるよう、SVG形式がおすすめです。

テキスト

QPainter::drawText関数で描画します。基本的な関数なのでお馴染みだと思いますので、詳細は割愛させていただきます。

テキストと画像を混在描画する

QPainter::fontMerticsという関数を使うとテキストを描画するための座標計算に使えるいろいろな情報を取得できます。今回重要なのはascentというパラメータで、テキストを描画する際のベースラインから文字の最上部までの高さを使います。

テキストと混ぜて描画したい画像のサイズを正方形と仮定すれば、画像のサイズは ascent × ascent です。画像を描画したら、次の座標を右方向に ascent 分進めることで、画像が文字であるかのように、文字送り処理を行います。

プログラム

ソースコードはGitHubに置きました。
https://github.com/soramimi/DrawEmojiText
Qt CreatorからDrawEmojiText.proを開いてビルドしてください。

使い方

Qtアプリケーションのリソースに:/image/sushi.svgという画像があるものとします。

次のような文字列を用意します。

"hoge&:/image/sushi.svg;fuga"
これを座標などと共にDrawEmojiText関数に渡します。

&;で囲まれた部分にリソース名を書きます。それ以外の部分は普通のテキストです。テキストの&を描画したい場合は、&&または&と書きます。

冒頭のサンプル画像は、次のようにして描画しています。

    QString text = "&:/image/cuctus.svg;Hello&:/image/sushi.svg;world&:/image/thinking.svg;";
    DrawEmojiText(&painter, x, y, text);

まとめ

文字列の構文解析と描画する座標計算がちょっと面倒な以外は、QPainter::drawTextQIcon::paintを交互に呼び出しているだけなので、実はたいしたことはしていません。