マルチバイト文字をビットマップとして取得し、表示したい。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
八田

マルチバイト文字をビットマップとして取得し、表示したい。

#1

投稿記事 by 八田 » 6年前

ここを使うのは初めてなので、テンプレで質問します。
[1] 質問文
 [1.1] 自分が今行いたい事は何か
  マルチバイト文字をビットマップとして取得し、表示したい。

 [1.2] どのように取り組んだか(プログラムコードがある場合記載)
  コードです。 http://marupeke296.com/WINT_GetGlyphOutline.html  を参考にしました。

コード:

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
	
	switch(msg) {
	case WM_LBUTTONDOWN:
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		//http://marupeke296.com/WINT_GetGlyphOutline.html 参考

		GLYPHMETRICS GM;
		CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}};

		HFONT hFont = CreateFont(
			150,
			0,
			0,
			0,
			0,
			FALSE,
			FALSE,
			FALSE,
			SHIFTJIS_CHARSET,
			OUT_TT_ONLY_PRECIS,
			CLIP_DEFAULT_PRECIS,
			PROOF_QUALITY,
			FIXED_PITCH | FF_MODERN,
			TEXT("MS ゴシック")
		);

		HDC hdc = GetDC(hwnd);
		HFONT oldFont = (HFONT)SelectObject(hdc, hFont);
		

		char *c = "あ";
		UINT code = 0;
		if(IsDBCSLeadByte(*c))//ダブルバイト文字か否か
			code = (BYTE)c[0]<<8 | (BYTE)c[1];// 2バイト文字のコードは[文字コード]*256 + [先導コード]
		else
			code = c[0];

		// ビットマップ取得
		DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, 0, NULL, &Mat);
		BYTE *ptr = new BYTE[size];
		GetGlyphOutline(hdc, code, GGO_GRAY8_BITMAP, &GM, size, ptr, &Mat);

		TEXTMETRIC TM;
		GetTextMetrics(hdc, &TM);

		DWORD pixel = 0;

		//ビットマップ表示
		for(UINT y = TM.tmAscent-GM.gmptGlyphOrigin.y; y < GM.gmBlackBoxY; y++){
			for(UINT x = GM.gmptGlyphOrigin.x; x < GM.gmBlackBoxX; x++){

				pixel = (DWORD)(y*GM.gmBlackBoxX + x);

				SetPixelV(hdc, x-GM.gmptGlyphOrigin.x, y-(TM.tmAscent-GM.gmptGlyphOrigin.y), (COLORREF)ptr[pixel]);
			}
		}

		// オブジェクトの開放
		SelectObject(hdc, oldFont);
		DeleteObject(hFont);
		ReleaseDC(hwnd, hdc);

		delete[] ptr;
	
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
		 PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	WNDCLASS winc;
	MSG msg;

	winc.style		    = CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	    = winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		    = LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(GRAY_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("WINC");

	if (!RegisterClass(&winc)) return 0;

	hwnd = CreateWindow(
			TEXT("WINC") , TEXT("test") ,
			WS_OVERLAPPEDWINDOW  | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return 0;

	while (GetMessage(&msg , NULL , 0 , 0)){
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
 [1.3] どのようなエラーやトラブルで困っているか(エラーメッセージが解る場合は記載)
  文字がずれて表示されます。表示方法が間違っているのだと思います。
  また、for文の条件式をいじるとヒープ不足と怒られます。
 [1.4] 今何がわからないのか、知りたいのか
  表示方法を知りたいです。いろいろ試したのですがヒープ不足と怒られたり、どうしても綺麗に表示されないのです。

[2] 環境  
 [2.1] OS : Windows10
 [2.2] コンパイラ名 : visual studio 2008

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#2

投稿記事 by みけCAT » 6年前

八田 さんが書きました:また、for文の条件式をいじるとヒープ不足と怒られます。
試しておらず予想ですが、サイズを得るときはGGO_GRAY4_BITMAP、実際に取得するときはGGO_GRAY8_BITMAPとフォーマットが違うのはまずそうな気がします。
GetGlyphOutlineのドキュメントを読んでいないので、勘違いだったらごめんなさい。


【追記】
GetGlyphOutline関数のドキュメントを読みました。
返されるデータは全部バイト配列のようなので、関係なさそうだと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

八田

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#3

投稿記事 by 八田 » 6年前

回答ありがとうございます。
問題ないとはいえ、定数が違うのはおかしいですね。修正します。

アバター
keito94
記事: 264
登録日時: 7年前
連絡を取る:

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#4

投稿記事 by keito94 » 6年前

>> みけCATさん
見当違いでしたね。今度は正しい回答ができるようにしましょう。
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

かずま

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#5

投稿記事 by かずま » 6年前

これではだめなんですか?

コード:

        for (UINT y = 0; y < GM.gmBlackBoxY; y++) {
            for (UINT x = 0; x <= GM.gmBlackBoxX; x++) {
                pixel = (DWORD)(y*(GM.gmBlackBoxX + 1)+ x);  // +1 に注意
                SetPixelV(hdc, x, y, (COLORREF)ptr[pixel]);
            }
        }
余談ですが、CreateFont は、WM_CREATE で 1回だけ実行して
DeleteObject は、WM_DESTROY で実行すればよいのでは?
もちろん、WM_PAINT の CreateFont と DeleteObject は削除します。

コード:

    switch(msg) {
    case WM_CREATE:
        static HFONT hFont = CreateFont(   // static に注意
            150, 0, 0, 0, 0, FALSE, FALSE, FALSE,
            SHIFTJIS_CHARSET,
            OUT_TT_ONLY_PRECIS,
            CLIP_DEFAULT_PRECIS,
            PROOF_QUALITY,
            FIXED_PITCH | FF_MODERN,
            TEXT("MS ゴシック")
        );
        return 0;
    case WM_LBUTTONDOWN:
    case WM_DESTROY:
        DeleteObject(hFont);
        PostQuitMessage(0);
        return 0;

かずま

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#6

投稿記事 by かずま » 6年前

かずま さんが書きました:

コード:

        for (UINT y = 0; y < GM.gmBlackBoxY; y++) {
            for (UINT x = 0; x <= GM.gmBlackBoxX; x++) {
                pixel = (DWORD)(y*(GM.gmBlackBoxX + 1)+ x);  // +1 に注意
                SetPixelV(hdc, x, y, (COLORREF)ptr[pixel]);
            }
        }
すみません。x <= を x < に訂正します。

八田

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#7

投稿記事 by 八田 » 6年前

>>かずま さん 
回答ありがとうございます。ずれずに表示させることができました。
おそらくfor文の初期化において、文字描画の位置だと勘違いしていました。
しかし、他の文字で試してみたところ、ずれる文字もありました。("い"等)

余談についてですが、修正したところ、
 ' hFont ' の初期化が 'case' ラベルによって行われませんでした。
とエラーが出たのでWM_CREATEを{}でくくったのですが、WM_PAINTでhFontが
認識されなくなったので、この修正はすみません、一旦おいておきます。

かずま

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#8

投稿記事 by かずま » 6年前

幅は 4の倍数でないといけないようです。
また、GGO_GRAY8_BITMAP にしました。

コード:

        DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY8_BITMAP, &GM, 0, NULL, &Mat);
        BYTE *ptr = new BYTE[size];
        GetGlyphOutline(hdc, code, GGO_GRAY8_BITMAP, &GM, size, ptr, &Mat);
 
        UINT w = (GM.gmBlackBoxX + 3) & ~3;
        for (UINT y = 0; y <= GM.gmBlackBoxY; y++) {
            for (UINT x = 0; x < GM.gmBlackBoxX; x++) {
                DWORD pixel = (DWORD)(y*w + x);
                SetPixelV(hdc, x, y, (COLORREF)ptr[pixel]);
            }
        }
hFont は、

コード:

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp)
{
    static HFONT hFont;   // ここで宣言
    switch(msg) {
    case WM_CREATE:
        hFont = CreateFont(   // static はつけない
            150, 0, 0, 0, 0, FALSE, FALSE, FALSE,
            SHIFTJIS_CHARSET,
            OUT_TT_ONLY_PRECIS,
            CLIP_DEFAULT_PRECIS,
            PROOF_QUALITY,
            FIXED_PITCH | FF_MODERN,
            TEXT("MS ゴシック")
        );
        return 0;

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#9

投稿記事 by みけCAT » 6年前

かずま さんが書きました:幅は 4の倍数でないといけないようです。
GetGlyphOutline 関数の「位置調整がダブルワード」ということでしょう。
4の倍数ということは、「ダブルワード」はDWORDのことですかね。

オフトピック
keito94 さんが書きました:>> みけCATさん
見当違いでしたね。今度は正しい回答ができるようにしましょう。

これいる?なんかムカつくなあ…

keito94 さんが書きました:⑤返事してくれたみんなにはお礼を言おう。

【審議中】 ( ´・ω) (´・ω・) (・ω・`) (ω・` )
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

八田

Re: マルチバイト文字をビットマップとして取得し、表示したい。

#10

投稿記事 by 八田 » 6年前

>>かずま さん
>>みけCAT さん
本当にありがとうございます。お二人の助言でプログラムを完成させることができました。

問題点は
・ビットマップの出力位置をfor文の初期化として考えてしまったこと
・幅をダブルワードで4の倍数になっていなかったこと
でした。

かずまさん、みけCATさんの助言をもとに修正したコードです。

コード:

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {

	static HFONT hFont;
	switch(msg) {

	case WM_CREATE:
		hFont = CreateFont(
			150,
			0,
			0,
			0,
			0,
			FALSE,
			FALSE,
			FALSE,
			SHIFTJIS_CHARSET,
			OUT_TT_ONLY_PRECIS,
			CLIP_DEFAULT_PRECIS,
			PROOF_QUALITY,
			FIXED_PITCH | FF_MODERN,
			TEXT("MS ゴシック")
		);
		return 0;
	case WM_LBUTTONDOWN:
	case WM_DESTROY:
		PostQuitMessage(0);
		DeleteObject(hFont);
		return 0;
	case WM_PAINT:
		// フォント情報
	
		//http://marupeke296.com/WINT_GetGlyphOutline.html 参考

		GLYPHMETRICS GM;
		CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}};

		HDC hdc = GetDC(hwnd);
		HFONT oldFont = (HFONT)SelectObject(hdc, hFont);
		
		char *c = "い";
		UINT code = 0;
		if(IsDBCSLeadByte(*c))//ダブルバイト文字か否か
			code = (BYTE)c[0]<<8 | (BYTE)c[1];// 2バイト文字のコードは[文字コード]*256 + [先導コード]
		else
			code = c[0];

		// ビットマップ取得
                //位置調整はDWORD
		DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY8_BITMAP, &GM, 0, NULL, &Mat);
		BYTE *ptr = new BYTE[size];
		GetGlyphOutline(hdc, code, GGO_GRAY8_BITMAP, &GM, size, ptr, &Mat);

		TEXTMETRIC TM;
		GetTextMetrics(hdc, &TM);

		//ビットマップ表示
		DWORD pixel = 0;
		UINT w = (GM.gmBlackBoxX + 3) & ~3;//4の倍数にする
		for(UINT y = 0; y < GM.gmBlackBoxY; y++){
			for(UINT x = 0; x < GM.gmBlackBoxX; x++){

				pixel = (DWORD)(y*w+x);

				SetPixelV(hdc, x, y, (COLORREF)ptr[pixel]);
			}
		}

		// オブジェクトの開放
		SelectObject(hdc, oldFont);
		ReleaseDC(hwnd, hdc);

		delete[] ptr;
	
		return 0;
	}
	return DefWindowProc(hwnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
		 PSTR lpCmdLine , int nCmdShow ) {
	HWND hwnd;
	WNDCLASS winc;
	MSG msg;

	winc.style		    = CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra	    = winc.cbWndExtra	= 0;
	winc.hInstance		= hInstance;
	winc.hIcon		    = LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(GRAY_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("WINC");

	if (!RegisterClass(&winc)) return 0;

	hwnd = CreateWindow(
			TEXT("WINC") , TEXT("test") ,
			WS_OVERLAPPEDWINDOW  | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			NULL , NULL ,
			hInstance , NULL
	);

	if (hwnd == NULL) return 0;

	while (GetMessage(&msg , NULL , 0 , 0)){
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
二人とも本当にありがとうございました!

返信

“C言語何でも質問掲示板” へ戻る