画像データへの簡易文字描画

デバッグ時に画像データにお手軽に文字情報を出力したいときなどが
たまにあったりなかったり。

ちゃっちゃと出力したときは、GDI+を使ってます。

int channel;
int width;
int height;
unsigned char* data = new unsigned char[width * height * channel];

////////////////////////////////////////////////////
// dataに文字描画.
// int x [i] 左上のx座標.
// int y [i] 左上のy座標.
// const char* string [i] 文字列.
// const char* fontName [i] フォント名.
// unsigned char r [i] フォント色R.
// unsigned char g [i] フォント色G.
// unsigned char b [i] フォント色B.
// int fontSize [i] フォントサイズ.(pt)

BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), width, height, 1, channel * 8 };

Gdiplus::Bitmap bmp*1;
wchar_t* wstring = new(std::nothrow) wchar_t[strlen(string) + 1];
MultiByteToWideChar(CP_ACP, 0, string, strlen(string) + 1, wstring, (strlen(string) + 1) * 2);
wchar_t* wfontName = new(std::nothrow) wchar_t[strlen(fontName) + 1];
MultiByteToWideChar(CP_ACP, 0, fontName, strlen(fontName) + 1, wfontName, (strlen(fontName) + 1) * 2);

Gdiplus::RectF rect(x, y, width - x - 1, height - y - 1);
Gdiplus::Font font(wfontName, fontSize);
Gdiplus::SolidBrush brush(Gdiplus::Color(r, g, b));
Gdiplus::StringFormat format;
graphics.DrawString(wstring, -1, &font, rect, &format, &brush);

if ( wstring ) delete wstring;
if ( wfontName ) delete
wfontName;

みたいなかんじ。

ワイド文字列バッファ確保を、new(std::nothrow) にしてるのは、
デバッグコードが例外投げられても困るからです。
wstring や wfontName が確保失敗でNULLでも、文字が描画されないだけで
その先の処理は進むし。

フォントサイズは、pt指定だけど、pixel指定にしたいなら、
fontSize = fontSize * dpi / 72;
とかにしたらいいんじゃないかな。
(このへんよくしらないです)

円描画なら、

////////////////////////////////////////////////////
// dataに楕円描画.
// int x [i] 左上のx座標.
// int y [i] 左上のy座標.
// int w [i] 横幅.
// int h [i] 縦幅.
// unsigned char r [i] フォント色R.
// unsigned char g [i] フォント色G.
// unsigned char b [i] フォント色B.
// int bold [i] 太さ.

BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), width, height, 1, channel * 8 };

Gdiplus::Bitmap bmp*2, bold);
graphics.DrawEllipse(&pen, x, y, w, h);

でいけるかな。

あと、GDI+を使う準備として、

#include
#pragma comment(lib, "gdiplus.lib")

struct CGdiplus
{
Gdiplus::GdiplusStartupInput input;
unsigned long token;

CGdiplus() { Gdiplus::GdiplusStartup(&token, &input, NULL); }
~CGdiplus() { Gdiplus::GdiplusShutdown(token); }
};

{
CGdiplus gdiplus;

// 処理.
}

てしとけばOK。

*1:PBITMAPINFO)(&bmi), data); Gdiplus::Graphics graphics(&bmp); graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); // アンチエイリアス. // GdiPlus::DrawStringが取りうる文字列の型がWCHAR* なので、 // char* → wchar_t* に変換. std::locale::global(std::locale("japanese"

*2:PBITMAPINFO)(&bmi), data); Gdiplus::Graphics graphics(&bmp); graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); // アンチエイリアス. Gdiplus::Pen pen(Gdiplus::Color(r, g, b