• ベストアンサー

GetGlyphOutline() ご利用経験者さま・・

文字を描画する GetGlyphOutline() を利用し文字列の描画をしたいのですが どうやっても上手く行きません。 1文字ずつ文字コード→文字画像を取得しているのですが、 1文字目だけが正常描画され、2文字目からは完全に別物の器に取得しても 文字が少しずつ等倍間隔でせり上がったり、時には x座標が突然大きくずれてループしてしまいます。 参考元URL : http://marupeke296.com/DXGSmp_No5_Font.html 上のURLの 「フォントビットマップ取得」 からの7行は 「1文字あたりの画像取得に関してのみ」ほぼそのまま利用しています。 わかっている事は、 ・この処理をクラス化しているのですが、「別のインスタンス」でも  常に1文字目だけは正常に取得されている事。 ・TEXTMETRIC TM;/GetTextMetrics/GLYPHMETRICS GM;/CONST MAT2 Mat  の4つを毎回完全に別物を定義して使っても、結果は変化なし。 ・手前のLOGFONT構造体 ~ デバイスコンテキストの取得~開放 までを、  「1文字毎の画像取得ループ」に入れても、結果に変化なし。 という事です。 別のインスタンスだと1文字だけ常に正しく取得できている事から 何かがリセット出来ていないのが原因だと思うのですが、思いつく限りの事は 全てやり、何が原因なのかわからなくなってしまいました。 可能性でも良いので、どうか解決策 or 同等の別方法が有れば教えて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8525/19382)
回答No.5

追記。 TM、GM構造体の中の「ベースラインや文字位置を示すメンバ」を「1文字ごとに参照」して、正しい位置に表示するには、以下のようにします。     px = Image1->Canvas->Pixels[x][y] & 0xff;          ↓     px = Image1->Canvas->Pixels[x + GM.gmptGlyphOrigin.x][y + TM.tmAscent - GM.gmptGlyphOrigin.y] & 0xff;      Image1->Canvas->Pixels[x][y] = (TColor)RGB(cl,cl,cl);          ↓      Image1->Canvas->Pixels[x + GM.gmptGlyphOrigin.x][y + TM.tmAscent - GM.gmptGlyphOrigin.y] = (TColor)RGB(cl,cl,cl); 単に「塗る座標が変わるだけ」で、他はなにも変わりません。 添付画像を見比べると、表示される文字の位置が「左上隅」から「イメージコントロールの中央」に変化し、上下の位置も「文字のベースライン」に揃ったのが判ると思います。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

その他の回答 (8)

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.9

>申し訳ないのですが、Image1の定義方法を教えて頂けないでしょうか; >BMP関係とまでは判ったのですが、インクルードすべきものが何なのかが未だわかりません; ソレは私のソースではないのですが…。 私のはSetPixel()で点を打つという速度度外視のものです。 >unsigned int(GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4); >という定番らしい計算式を取り込んで計算しています。(4の倍数問題) Bitmapには4の倍数境界ありますが… GetGlyphOutline()で取得したデータに4の倍数境界なんてありましたかね? プロポーショナルピッチフォントだった場合、とんでもないことになるような気がしますが。

zaxs5968
質問者

お礼

>ソレは私のソースではないのですが…。 あれ・・申し訳ありませんでした; >GetGlyphOutline()で取得したデータに4の倍数境界なんてありましたかね? 参考にしたサイトの中でそういう風に計算すると説明があったので 鵜呑みにしてしまったのですが、 まずかったのでしょうか。 これだけあれこれ教えて頂いていていつつも 頂いたソースすらまともに動かせず どんどん頭の中がテンパってき誤爆レスまでしてすいません。 明日(というか今日)1日やってみて駄目だったら諦めて 別の方法を探す事にします。お騒がせして申し訳ありませんでした。 色々教えて下さって本当にありがとうございました。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.8

#3です。 あるいは全然別の可能性として、1文字目の描画処理の際に、バッファオーバーフローかなんかを起こして、どこかの変数を破壊してしまった結果、2文字目以降の描画がうまくいかないとか。

zaxs5968
質問者

お礼

// つづき 入りきれず省略多 SelectObject(hdc, oldFont); DeleteObject(hFont); ReleaseDC(NULL, hdc); // DirextX部分(省略) D3DLOCKED_RECT LockedRect; pTex->LockRect(0, &LockedRect, NULL, D3DLOCK_DISCARD); pTex->LockRect(0, &LockedRect, NULL, 0); // メモリ書込 ptr→Alpha DWORD Alpha, Color; int x, y; int k = 0; int cell_xtotal = 0; int f_change = iCell_x[0]; FillMemory(LockedRect.pBits, LockedRect.Pitch * i_totaly, 0); for(y=0; y<i_totaly; y++) for(x=0; x<i_totalx; x++){ Alpha = 0; // 一周毎初期化 if ( x==0 ) { k=0; cell_xtotal=0; f_change = iCell_x[0];} // 次の文字範囲 if(x>=f_change){ cell_xtotal+=iCell_x[k]; k++; f_change +=iCell_x[k];} // 最大文字数確認 if( k >= (f_count)) { Alpha = 0; } else { // y座標確認 if (y < iOfs_y[k]) { Alpha = 0; } else { // x座標確認 // if( x >= iOfs_x[k] && x < iBmp_w[k]) { if( x >= (iOfs_x[k] + cell_xtotal) && x < (iBmp_w[k] + iOfs_x[k] + cell_xtotal)) { Alpha = 0; if ( k == 0 ) { Alpha = (255 * ptr0[x-iOfs_x[k] + iBmp_w[k]*(y-iOfs_y[k])]) / (Level-1); } if ( k == 1 ) { Alpha = (255 * ptr1[x-iOfs_x[k] + iBmp_w[k]*(y-iOfs_y[k])]) / (Level-1); } if ( k == 2 ) { Alpha = (255 * ptr2[x-iOfs_x[k] + iBmp_w[k]*(y-iOfs_y[k])]) / (Level-1); } if ( k == 3 ) { Alpha = (255 * ptr3[x-iOfs_x[k] + iBmp_w[k]*(y-iOfs_y[k])]) / (Level-1); } if ( k == 4 ) { Alpha = (255 * ptr4[x-iOfs_x[k] + iBmp_w[k]*(y-iOfs_y[k])]) / (Level-1); } if ( k == 5 ) { Alpha = (255 * ptr5[x-iOfs_x[k] + iBmp_w[k]*(y-iOfs_y[k])]) / (Level-1); } } else { Alpha = 0; } } } Color = 0x00ffffff | (Alpha<<24); memcpy((BYTE*)LockedRect.pBits + LockedRect.Pitch*y + 4*x, &Color, sizeof(DWORD)); } pTex->UnlockRect(0); // テスクチャ(省略) return S_OK; } void FontPict::FontPictDraw(LPDIRECT3DDEVICE9 pD3DDevice) { // 描画 }

zaxs5968
質問者

補足

何かそんな気がします。 ・画像の取得は頂いたサンプルと見比べ問題はありませんでした。 ・描画座標は、描画の始点(x.y) 描画する範囲 セルの範囲(全角半角毎に同数)  3つの取得した数値も、最終描画位置もピクセル単位で数えて計測し  問題はありませんでした。 そして今は1文字ずつ 012345 と  BYTE* ptr0 = new BYTE[2048]; // 1文字確実に治まるサイズ 器を作っていますが、以前  BYTE* ptr = new BYTE[20480]; としてBYTE[0] [2000] [4000]と1文字2000間隔で入れていた時も同じ症状でしたが、 書き出す位置を「1文字x -45」するとy軸のずれはかなり治まっていたので (x座標が飛んで変なループする症状が有ったのでそれはやめましたが。) その 『1文字 -45BYTE』 というのが何かそういう バッファオーバーフローなる現象なのかも と思えたりします。 汚い上、DirectX SDK 2006年4月版を使っているものですが、 ソースを・・ (Makeは1度きり。Drawはループ中でBeginScene~EndScene間で呼出ししています) ---------------------------------------------------------------- #include <Tchar.h> #include "FontPic.h" #define TEXTL 50 // 最大文字数(予定) struct CUSTOMVERTEX{ float x,y,z; // 頂点座標 float rhw; // 除算数 DWORD dwColor; // 頂点の色 float u, v; // テクスチャ座標 }; FontPict::FontPict() { } FontPict::~FontPict() { } HRESULT FontPict::FontPictMake(LPDIRECT3DDEVICE9 pD3DDevice, float vposx, float vposy, char* tname) { int iOfs_x[TEXTL]; int iOfs_y[TEXTL]; int iBmp_w[TEXTL]; int iBmp_h[TEXTL]; int iCell_x[TEXTL]; BYTE* ptr0 = new BYTE[2048]; BYTE* ptr1 = new BYTE[2048]; BYTE* ptr2 = new BYTE[2048]; BYTE* ptr3 = new BYTE[2048]; BYTE* ptr4 = new BYTE[2048]; BYTE* ptr5 = new BYTE[2048]; // フォントの生成 int fontsize = 41; LOGFONT lf = {fontsize, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, _T("MS 明朝")}; HFONT hFont; if(!(hFont = CreateFontIndirect(&lf))){ pD3DDevice->Release(); //g_pD3D->Release(); return 0; } HDC hdc = GetDC(NULL); HFONT oldFont = (HFONT)SelectObject(hdc, hFont); // フォント画像取得へ int Level = 17; TCHAR p[] = _T("AB・12"); int char_num = sizeof p /sizeof p[0] -1; TCHAR *c = p; UINT code = 0; TEXTMETRIC TM; GetTextMetrics( hdc, &TM ); GLYPHMETRICS GM; CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}}; int f_count = 0; // 文字数のカウント bool twobitcs = true; // 全角判定フラグ int i; int i_totalx = 0; // 全文字での幅 int i_totaly = 0; // 同高さ(1行仕様なので1文字サイズ) for(i=0; i<char_num; i++) { UINT code = 0; #if _UNICODE code = (UINT)*c; #else if(IsDBCSLeadByte(c[i]) && (twobitcs)) { code = (BYTE)c[i]<<8 | (BYTE)c[i+1]; twobitcs=!twobitcs; } else if (!twobitcs) { twobitcs=!twobitcs; continue; } else code = c[i]; #endif memset(&GM, 0x00, sizeof(GLYPHMETRICS)); DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, 0, NULL, &Mat); if (f_count == 0 ) { hr = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, &ptr0[0], &Mat); } if (f_count == 1 ) { hr = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, &ptr1[0], &Mat); } if (f_count == 2 ) { hr = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, &ptr2[0], &Mat); } if (f_count == 3 ) { hr = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, &ptr3[0], &Mat); } if (f_count == 4 ) { hr = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, &ptr4[0], &Mat); } if (f_count == 5 ) { hr = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, &ptr5[0], &Mat); } // Ofs=描画始点 Bmp=画像範囲 Cell=セル横幅 iOfs_x[f_count] = int(GM.gmptGlyphOrigin.x); iOfs_y[f_count] = int(TM.tmAscent - (GM.gmptGlyphOrigin.y)); iBmp_w[f_count] = unsigned int(GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4); iBmp_h[f_count] = unsigned int(GM.gmBlackBoxY); iCell_x[f_count] = GM.gmCellIncX; i_totalx += GM.gmCellIncX; i_totaly = TM.tmAscent; f_count++; }

  • chie65535
  • ベストアンサー率43% (8525/19382)
回答No.7

以下の2つの関数を試してみて下さい。 (ソースをそのままコピペしたので、インデントが消えてます) //--------------------------------------------------------------------------- //文字列、フォント名、フォントサイズを指定して、必要なバッファのサイズを求める //Widthが横のバイト数 //Heightが縦のバイト数 void GetSize(char *str,char *FaceName,int FontSize,unsigned int *Width,unsigned int *Height) { char *p; unsigned int wd = 0; LOGFONT lf = {FontSize, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, "MS 明朝"}; strcpy(lf.lfFaceName,FaceName); HFONT hFont; if ((hFont = CreateFontIndirect(&lf)) == 0) return; HDC hdc = GetDC(NULL); HFONT oldFont = (HFONT)SelectObject(hdc, hFont); UINT code = 0; TEXTMETRIC TM; GetTextMetrics( hdc, &TM ); *Height = TM.tmHeight; GLYPHMETRICS GM; CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}}; for (p = str;*p;p++) { if ((*p < 0) && ((*p <= -96) || (*p >= -32))) { code = (*p++ << 8); code |= (*p & 0xff); } else { code = *p; } DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, 0, NULL, &Mat); if (size) wd += GM.gmCellIncX; } SelectObject(hdc, oldFont); DeleteObject(hFont); ReleaseDC(NULL, hdc); *Width = wd; } //--------------------------------------------------------------------------- //bufにビットマップを作る //文字列、フォント、フォントサイズ(第1~第3引数)は、GetSizeの呼び出し時と同じ引数を与えること //GetSizeの呼び出し時と食い違った場合は動作不定 //bufの中身は「横Width×縦Heightピクセルで、0~255のデータ」になる //そのまま「256階調のグレースケールのデータ」として使える //buf[0]~buf[Width - 1]が1ライン目 //buf[Width]~buf[Width * 2 - 1]が2ライン目 //buf[Width * 2]~buf[Width * 3 - 1]が3ライン目 //「256階調のグレースケール」のBMPヘッダを付けた上で、一番下のライン⇒一番上のラインの順でファイルに保存すれば「256階調のグレースケールのBMPファイル」になる void MakeImage(char *str,char *FaceName,int FontSize,char *buf,unsigned int Width,unsigned int Height) { char *p; LOGFONT lf = {FontSize, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, "MS 明朝"}; strcpy(lf.lfFaceName,FaceName); HFONT hFont; if ((hFont = CreateFontIndirect(&lf)) == 0) return; HDC hdc = GetDC(NULL); HFONT oldFont = (HFONT)SelectObject(hdc, hFont); UINT code = 0; TEXTMETRIC TM; GetTextMetrics( hdc, &TM ); GLYPHMETRICS GM; CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}}; memset(buf,255,Width * Height); int xx = 0; for (p = str;*p;p++) { if ((*p < 0) && ((*p <= -96) || (*p >= -32))) { code = (*p++ << 8); code |= (*p & 0xff); } else { code = *p; } DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, 0, NULL, &Mat); BYTE *ptr = new BYTE[size]; GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, ptr, &Mat); int ya = size / GM.gmBlackBoxY; for (unsigned int y = 0;y < GM.gmBlackBoxY;y++) { for (unsigned int x = 0;x < GM.gmBlackBoxX;x++) { buf[x + xx + GM.gmptGlyphOrigin.x + (y + TM.tmAscent - GM.gmptGlyphOrigin.y) * Width] = (char)(255 - ptr[ya * y + x] * 255 / 16); } } delete ptr; xx += GM.gmCellIncX; Image1->Refresh(); } SelectObject(hdc, oldFont); DeleteObject(hFont); ReleaseDC(NULL, hdc); } //--------------------------------------------------------------------------- 呼び出し方 unsigned int Width,Height; GetSize("文字列ABCDE","MS 明朝",500,&Width,&Height); char *buf = new char[Width * Height]; if (buf) { MakeImage("文字列ABCDE","MS 明朝",500,buf,Width,Height); } //newしたデータはdeleteする delete buf; 【注意】 「文字列が長く、かつ、フォントサイズが大きい」と「Width * Height」が「intまたはsize_tで表わせる値をオーバーする可能性がある」ので注意。オーバーフローした場合、動作は不定。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.6

ソースの例とか十分に付いている気がしないでもないですがせっかくなので。 VS2005でプロジェクトを作成、Win32プロジェクトでWin32アプリケーションを。 WndProcに以下を追加でとりあえず動作します。 UNICOE版でないとうまく動かないので注意が必要です。 # おそらくインデント消えているので適宜修正してください。 case WM_LBUTTONDOWN: { HDC hDC; LOGFONT lf = {32, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_MODERN, _T("MS P明朝")}; TEXTMETRIC TM = {0}; GLYPHMETRICS GM = {0}; MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}}; DWORD dwSize = 0, dwMaxSize = 0, dwErr = 0; BYTE *lpBuff = NULL, *lpGlyph; LPTSTR lpDrawString = _T("GetGlyphOutline() ご利用経験者さま・・"); LPTSTR lpTemp = NULL; UINT uiCode; POINT ptCursor; HFONT hFont = NULL, hOldFont = NULL; // 描画開始位置はクリックした座標 ptCursor.x = LOWORD(lParam); ptCursor.y = HIWORD(lParam); // DeviceContext設定 hDC = GetDC(hWnd); hFont = CreateFontIndirect(&lf); hOldFont = (HFONT)SelectObject(hDC, hFont); GetTextMetrics( hDC, &TM ); // バッファの最大サイズを調べる for(lpTemp = lpDrawString;*lpTemp;lpTemp++) { uiCode = (UINT)*lpTemp; dwSize = GetGlyphOutline(hDC, uiCode, GGO_GRAY8_BITMAP, &GM, 0, NULL, &Mat); if(dwSize == GDI_ERROR) { dwErr = GetLastError(); } else { if(dwSize > dwMaxSize) dwMaxSize = dwSize; } } // 実データ取得&描画 if(dwMaxSize != 0) { lpBuff = (BYTE *)malloc(dwMaxSize); for(lpTemp = lpDrawString;*lpTemp;lpTemp++) { uiCode = (UINT)*lpTemp; dwSize = GetGlyphOutline(hDC, uiCode, GGO_GRAY8_BITMAP, &GM, dwMaxSize, lpBuff, &Mat); if(dwSize != GDI_ERROR) { DWORD dwXSize, dwLevel, dwDrawx, dwDrawy; dwXSize = GM.gmBlackBoxX; if(dwSize != (GM.gmBlackBoxX * GM.gmBlackBoxY)) { // 取得したサイズとデータサイズが違う… // chie65535さんも指摘している箇所 dwXSize = dwSize / GM.gmBlackBoxY; } lpGlyph = lpBuff; for(dwDrawy = 0;dwDrawy < GM.gmBlackBoxY;dwDrawy++) { for(dwDrawx = 0;dwDrawx < dwXSize;dwDrawx++, lpGlyph++) { dwLevel = 0; if(*lpGlyph != 0) { dwLevel = (*lpGlyph) * 4 - 1; SetPixel(hDC, ptCursor.x + dwDrawx + GM.gmptGlyphOrigin.x, ptCursor.y + dwDrawy + TM.tmAscent - GM.gmptGlyphOrigin.y, RGB(255, 255 - dwLevel, 255 - dwLevel)); } } } // 1文字分座標を加算 ptCursor.x += GM.gmCellIncX; } else if(GetLastError() == NO_ERROR){ // GDI_ERRORなのにGetLastError()はNO_ERROR… ptCursor.x += TM.tmAveCharWidth; } } // 使用済みバッファを解放 free(lpBuff); } // 後始末 SelectObject(hDC, hOldFont); DeleteObject(hFont); ReleaseDC(hWnd, hDC); } break; > ># 念のためGLYPHMETRICS構造体は0x00で埋めてから渡す…とか。 > すみません、構造体の扱いに慣れておらず、 > できれば埋め方のコードを教えて頂けませんでしょうか? > 値のリセット方法がわからず、別の確認方法でかなり手間がかかったもので; memset(&GM, 0x00, sizeof(GLYPHMETRICS)); のように使います。 なお、Win32APIだとこれで0x00で埋めただけの構造体のアドレスを渡すとうまくいかないモノもありますので注意が必要です。 構造体の最初のメンバに「この構造体のサイズ」を設定するモノなど……。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

zaxs5968
質問者

補足

構造体の埋め方、ありがとうございます。 memset関数・・覚えておきます。使い方に注意も必要なのですね。 そして頂いた上のコードなのですが、 申し訳ないのですが、Image1の定義方法を教えて頂けないでしょうか; BMP関係とまでは判ったのですが、インクルードすべきものが何なのかが未だわかりません; 描画はDirectXのテスクチャに頼り切ってしまっていて、申し訳ありません;

  • chie65535
  • ベストアンサー率43% (8525/19382)
回答No.4

もしかして「2文字目以降は、1文字目と同じ大きさのビットマップが返って来る」とか思ってませんか? 1文字目に「17×18ピクセル(360バイト)」のビットマップが返された後、2文字目もそうなるとは限りません。 2文字目が「・」とかであれば、2文字目は「5×5ピクセル(40バイト)」のビットマップが返って来るかもしれません。 どのような構造(縦横が何ピクセル)のビットマップが返って来るかは「1文字ごとに、GM構造体の中を参照」しなければなりません。 「2文字目以降がおかしい」と思ったのは「GM構造体の中身が毎回変わらない」と思い込んだからではないでしょうか? 以下のような「連続でフォントを取得して、イメージコントロールに描画するルーチン」で試した所、正しく動いてます。 void ImagePut(char *str) {  char *p;  int fontsize = 500;  LOGFONT lf = {fontsize, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS,  CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FIXED_PITCH | FF_MODERN, "MS 明朝"};  HFONT hFont;  if ((hFont = CreateFontIndirect(&lf)) == 0) return;  HDC hdc = GetDC(NULL);  HFONT oldFont = (HFONT)SelectObject(hdc, hFont);  UINT code = 0;  TEXTMETRIC TM;  GetTextMetrics( hdc, &TM );  GLYPHMETRICS GM;  CONST MAT2 Mat = {{0,1},{0,0},{0,0},{0,1}};  //strの終端まで繰り返す  for (p = str;*p;p++) {   if ((*p < 0) && ((*p <= -96) || (*p >= -32))) {    code = (*p++ << 8);    code |= (*p & 0xff);   } else {    code = *p;   }   //必要なバッファサイズは「1文字ごと」に違う   DWORD size = GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, 0, NULL, &Mat);   //必要なバッファは毎回動的に確保する   BYTE *ptr = new BYTE[size];   GetGlyphOutline(hdc, code, GGO_GRAY4_BITMAP, &GM, size, ptr, &Mat);   int cl,px;   //yaはバッファの1ライン分のバイト数   int ya = size / GM.gmBlackBoxY;   if ((ya != GM.gmBlackBoxX) || (ya * GM.gmBlackBoxY != size)) {    //GetGlyphOutlineから返されたsizeの値がおかしい    //ここで何らかの対処をして、正しいyaを求めること   }   for (unsigned int y = 0;y < GM.gmBlackBoxY;y++) {    for (unsigned int x = 0;x < GM.gmBlackBoxX;x++) {     cl = 255 - ptr[ya * y + x] * 255 / 17;     px = Image1->Canvas->Pixels[x][y] & 0xff;     //「より黒いピクセル」のみ塗る     if ((cl != 255) && (px > cl)) {      // Image1->Canvas->Pixels[x][y]は表示用のイメージコントロール      Image1->Canvas->Pixels[x][y] = (TColor)RGB(cl,cl,cl);     }    }   }   delete ptr;   //1文字塗るたびに表示用のイメージコントロールを再描画   Image1->Refresh();  }  SelectObject(hdc, oldFont);  DeleteObject(hFont);  ReleaseDC(NULL, hdc); }

zaxs5968
質問者

お礼

>もしかして「2文字目以降は、1文字目と同じ大きさのビットマップが返って来る」とか思ってませんか? いえ、 GetGlyphOutline で検索し出た資料3~4つに目を通し iOfs_x[f_count] = int(GM.gmptGlyphOrigin.x); iOfs_y[f_count] = int(TM.tmAscent - (GM.gmptGlyphOrigin.y)); iBmp_w[f_count] = unsigned int(GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4); iBmp_h[f_count] = unsigned int(GM.gmBlackBoxY); iCell_x[f_count] = GM.gmCellIncX; 等としてそこから描画しています。 >頂いたコード あれこれやったのですが知識不足で 上手く動かす事はできませんでしたが、やはり画像取得までは同じようでした。 この関数に何か特殊な仕様でもあるのかなぁと 途方にくれていましたが、ちゃんと描画できるという事は、 私が何か間違えてるのですし No5で頂いたコードと合わせて描画まわりと座標の取得を見比べさせて頂いて 解決を目指してみます。 返答が遅れて申し訳ありません(色々やってみて動かせなくてすいません;) ご回答ありがとうございます。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.3

「一文字目」というのは、違う文字でも、正しく取得できるのでしょうか。 なんとなく取得そのものは正常にできているように思えます。 gm.gmBlackBoxXをDWORD単位にするのを忘れていたりしませんか? 描画部分も含めたソースを全部載せたほうが的確な回答が得られるかもしれません。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

zaxs5968
質問者

補足

お返事遅くなりました。 >「一文字目」というのは、違う文字でも、正しく取得できるのでしょうか。 はい。 全角でも半角でも何でも1文字目は正しく描画されています。 >gm.gmBlackBoxXをDWORD単位 現在は unsigned int(GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4); という定番らしい計算式を取り込んで計算しています。(4の倍数問題) >ソースを全部 DirectXを利用してしまっていますが、 もう少し頑張って解決できなかったら考えさせて頂こうかと思います。 ご回答ありがとうございました。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

描画位置については… http://marupeke296.com/WINT_GetGlyphOutline.html に詳しく書かれてます。 http://www.greenwood.co.jp/~k-aki/article/ggo_trap/index.html 環境によってはヘンな動作する…らしい。(なんという迷惑な…) 時間があれば簡単なサンプルでも作ってみるところなのですが…。 # 2つ目のURLでの指摘部分は無視したものになるでしょうけど。 睡眠時間足りてないのでちょっと無理です。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

zaxs5968
質問者

補足

>描画位置について 描画位置に関しては私もそのサイトを参考にさせて頂きました。 No1様の補足に書かせて頂きましたが、計算は正しくできていると思えます。 >環境によってはヘンな動作 やはり使わない方が良い関数という事なのですかね・・。 8日潰しただけに諦めるのがもったいないような、代替関数が無いか 探してはいるのですが・・。 >簡単なサンプル 切実にお願いしたく思えたりします・・。 以前1つのBYTEに[0] [2000] [4000] [6000]と1文字ずつ入れた時も 同様のせり上がり方をしたので その時は無理やり表示する時に-45程し、並んでるかのようにはなったのですが、 x座標が激しくずれてループしたりして 1文字1つの宣言済みBYTEに入れるようにしました。 ・1文字ずつバッファの書き込まれる位置が-45程手前にずれている ・x座標が不規則(同じ文字列ならば固定位置)に  正常なのと大きくずれているのが混在してしまう となっています。 別のインスタンスでも1文字ずつは正しく取得できるのですし、 ちょっと無茶をして1文字1インスタンスで確保しまくって上手く行くか 試してみようと思います。 ご助言ありがとうございます。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

最後に触ったのがかなり前なので、あやふやですが… # 手元の練習用ソースをgrepしたが…残っていなかった。 >参考元URL : ​http://marupeke296.com/DXGSmp_No5_Font.html​ >上のURLの 「フォントビットマップ取得」 からの7行は >「1文字あたりの画像取得に関してのみ」ほぼそのまま利用しています。 ptrで確保しているBYTE[]はその都度解放/確保しなおしているか? 必要とするバッファのサイズは文字ごとに変わります。 プロポーショナルピッチのフォントで「I」と「O」では幅が違いますし。 幅の違い以外に高さの違いもバッファサイズに影響したはずです。 「O」と「-」で取得できるグリフの高さが違ったはず。 # 描画位置などについてはGLYPHMETRICS構造体で受け取れる。 ## 描画したい文字を一通りチェックて、取得したサイズのうち最大のものが収まるバッファを確保して使い回す。 ## というのはアリでしょう。 ## 確保/解放を繰り返した場合のオーバーヘッドや、メモリ領域のフラグメント回避にはよいかと。 グリフ取得時のGetGlyphOutline()の戻り値はチェックしているか? エラー処理に必要かと。 とりあえず気になったのはこの2点くらいでしょうか。 # 念のためGLYPHMETRICS構造体は0x00で埋めてから渡す…とか。

zaxs5968
質問者

お礼

ご回答ありがとうございます。

zaxs5968
質問者

補足

>BYTE[]の開放/確保 原因究明の為に今は、BYTE ptr0[2048]; BYTE ptr1[2048]; ~ 2 3 4 5 6 と全部宣言しています。 器を入れ替えても1文字目だけは正しく描画されるので、器には問題無いと思います。 >文字の描画範囲 描画関係は GM.gmptGlyphOrigin.x/y GM.gmBlackBoxX/Y GM.CellIncX TM.tmAscent らを計算後、1文字ずつ配列に保存し、それに従って計算し描画しています。 書き忘れてすいません; >GetGlyphOutline()の戻り値 MSDNに記載されていた 0 GDI_ERROR のみですがチェックしてみましたが HRESULTで受け取った値は560等の実数で、正常動作のようです。 ># 念のためGLYPHMETRICS構造体は0x00で埋めてから渡す…とか。 すみません、構造体の扱いに慣れておらず、 できれば埋め方のコードを教えて頂けませんでしょうか? 値のリセット方法がわからず、別の確認方法でかなり手間がかかったもので;

関連するQ&A

  • VC2008にてフォントの変更がうまくいきません

    環境  WindowsXP  VC 2008 MFC   内容  上記の環境化で、ウインドウズアプリケーションを作成しており  以下のようなプログラムをOnInitDialogでCallすると  アサートが発生してしまいます  問題なのは、Unicodeでコンパイルして実行するとうまくいかず  マルチバイトでコンパイルするとうまく行きます。  ご教授願います。 エディットコントロールの派生クラスにて 以下の内容を実行しています LOGFONT m_logfont; ←コンストラクタでコントロールから取得済み CFont m_font;←コンストラクタで設定済み BOOL エディットコントロールの派生クラス::SetTextFont( int width, int height) {    ::_tcscpy_s(m_logfont.lfFaceName,sizeof(m_logfont.lfFaceName),_T("MS ゴシック"));   m_logfont.lfHeight = height; m_logfont.lfWidth = width; // m_font.DeleteObject(); // 現在のフォントの削除 // フォントを作成 m_font.DeleteObject(); if( m_font.CreateFontIndirect(&m_logfont) ){ SetFont(&m_font); } // ウィンドウを再描画 return RedrawWindow(); }

  • java + DB2/400の開発経験者の方に質問です。

    java + DB2/400の開発経験者の方に質問です。 java.sql.ResultSetMetaDataからDB2/400のデータ型を取得したいです。 DB2/400のフィールドのデータ型は数値であればPやS、文字であればAやJといった物がありますが、 その情報を実行時にjava.sql.ResultSetMetaDataのインスタンス等から取得できないでしょうか。 また別の方法でも取得する事が可能であれば、是非お教えいただきたいです。 非常に限定された要件になると思うのですが、よろしくお願いします。

  • DirectXのフォントについて

    現在、DirectX と C++でオリジナルのシューティングゲームを作っています。 そこで、スコアや画面で文字(文)を表示したいのですが、 使うフォントを環境に依存しないようにしたいのです。 D3DXFontなどで文字描画はできますが、それは使うPCに入っているフォントしか表示できませんよね? 市販や同人のゲームを見ていると、「MS 明朝」などではなくオリジナル、あるいは製作されたフォントを使っているようにしか思えません。 フォントを配布された覚えもありません。 一つ一つの文字を画像にして、それから「画像として」表示する、という方法もありますが、それでは漢字の処理がかなり面倒なことになると思うのです。 つまり、「PCに入っていないフォントをゲーム中で自由に表示できる(ように見せかける)」方法が分からないのです。 やはり文字一つ一つを画像にするしかないのでしょうか。 それとも別の方法があるのでしょうか。 ご回答お願いします。 実際に作品を作っているサークルの方の回答もあれば嬉しい限りです。

  • フォント画像の取得方法

    BYTE配列にフォント画像を取得する関数をご存知の方がいましたら 教えて頂けると幸いです。 ウィンドウハンドルから直接描画する方法しか見つかりません orz

  • GetTextExtentPoint32での高さ

    こんにちは。 数字が入った文字列をGetTextExtentPoint32関数で幅と高さを取得しようとすると、幅は正しく取得できるのですが、高さが倍近い値で返ってきてしまいます。どうやら高さはフォント全体の高さで取得しているようです。"0123"と"0123j"をセットしても同じ高さが返ってきます。 これを実際の描画範囲で取得するにはどうすればよろしいのでしょうか?

  • iアプリ、それともJava(?)における文字表示の挙動について

    iアプリ、それともJava(?)における文字表示の挙動について public void run(){  Graphics g = getGraphics();  while(true){   g.lock();   int i = 1;   g.drawString("hogehoge",0,15 + i); //下にずれて表示されていく。   g.unlock(true);   i++;  }//while() }//run() 【質問】 whileループで繰り返し、上記のような処理がなされる場合、 一度表示した文字は残らず、ループの繰り返し毎に、 何も表示されていない所に、1から表示しなおされる形で、 処理が行われています。 例えば、ループなしの簡単なHellow World!のような文字表示サンプルプログラムですと、 そのHellow World!という文字列を1度描画したら、そのまま描画されたままですが、 whileループの場合、 ループごとに、真っ白な状態に初期化され、その上に次の描画が行われ…ということを、 繰り返しているようです。 この時の、「毎回のループの初めに行われているであろう、真っ白な状態への初期化」は、 どういった仕組みで行われているのでしょうか? 別の言い方で言うと、 「whileループの描画処理が、蓄積されていかないのは何故?また、その蓄積がなされない理由(しくみ)はどこに?」 となります。 上記whileループの挙動に対し、 文字と文字が重なっていく、とか、 上段から下段へと文字がどんどん蓄積されながら描画されていく、 なんてことを想定していたわけですが、 実際には、そうはならないため、質問をさせて頂きました。、 このあたりのことについて、どなたか、お分かりになる方、ご教示下さい。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • BYTEの配列の扱いについて

    すみません、BYTEを初めて利用している者なのですが、 文字列の描画で BYTE* ptr = new BYTE[20480]; と宣言した中に、 GetGlyphOutline() で取得した文字の画像を、1文字ずつ &ptr[0]  &ptr[2000]  &ptr[4000]  &ptr[6000] ・・・ と2000毎に文字を入れ、書き出す時もそうしているのですが、 1文字目はキレイに描画できるのですが、2文字目以降が崩れてしまいます。 変なループが起きたり、文字毎に下に隙間が等倍で増えていく感じです。 これはBYTEの使い方を誤っていて、無理な使い方をしているのでしょうか? また、以前の質問でバイトも配列?が使えると聞いたのですが、 BYTE* ptr = new BYTE[1048 * 10]; これは BYTE* ptr = new BYTE[10480];  これと全く同じ物という意味なのでしょうか?

  • Visual Web Developerで描画

    こんばんは Visual Web Developerを初めて間もない者です。 Imageに文字列を描画したいと思っています。 例えば Textboxに入力した文字列をButtonイベントで取得して Imageで表示している画像上に描画 のような感じです。 その他の制約としましては、 ・画像サイズに合わせて文字列が折り返して描画されること どなたかご教授お願いいたします。 開発環境 ・Window XP Home Edition ・VWD 2010 Express(ASP.NET Webサイト C#)

  • 「VC++6」ウィンドウの再描画

    VC++6を使って簡単なプログラムをダイアログベース作っています。 内容はリストを読み込み、1件ずつDBにSQLを発行して情報を取得していくという内容です。 画面には、プログレスバーも設置しており、普通に操作すると正常に、プログレスバーも動きます。しかし、いったん別のウィンドウをアクティブにして、作成した動作中のプログラムを再選択しても、画面は壊れたまま再描画されません。しばらくまって、リストのSQL発行が終わって、画面に結果が表示されたら、きちんと再描画されます。 そこまで処理が終わったら、他のウィンドウに切り替えて戻ってきても画面が壊れることはありません。 時間がかかるプログラムなので、動作中に別の仕事をするため、アクティブでなくても、きちんとウィンドウを更新したいのです。 ちなみに、ループ処理中にRedrawWindow();を入れてみましたがダメでした。 アドバイスよろしくお願いします。

  • Fireworksで日本語文字に欧文フォントを選んでも問題ないですか?

    Fireworks(MX2004)などの画像処理ソフトで画像中に使用する日本語文字に欧文フォントを選んでもそれらの日本語文字はちゃんとレンダリングされますが、どういうことなのでしょうか? 通常、欧文フォントは英字(1バイト文字)にしか使えないような気がしますが。 Fireworksなどの画像処理ソフトで日本語文字を欧文フォントでレンダリングしても問題等起こらないのでしょうか? 関連サイト等ありましたらURLもお教えください。 よろしくお願いします。