dポイントプレゼントキャンペーン実施中!

文字を描画する 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 同等の別方法が有れば教えて下さい。

A 回答 (9件)

追記。



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);

単に「塗る座標が変わるだけ」で、他はなにも変わりません。

添付画像を見比べると、表示される文字の位置が「左上隅」から「イメージコントロールの中央」に変化し、上下の位置も「文字のベースライン」に揃ったのが判ると思います。
「GetGlyphOutline() ご利」の回答画像5
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/05/26 20:37

>申し訳ないのですが、Image1の定義方法を教えて頂けないでしょうか;


>BMP関係とまでは判ったのですが、インクルードすべきものが何なのかが未だわかりません;

ソレは私のソースではないのですが…。
私のはSetPixel()で点を打つという速度度外視のものです。


>unsigned int(GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4);
>という定番らしい計算式を取り込んで計算しています。(4の倍数問題)

Bitmapには4の倍数境界ありますが…
GetGlyphOutline()で取得したデータに4の倍数境界なんてありましたかね?
プロポーショナルピッチフォントだった場合、とんでもないことになるような気がしますが。
    • good
    • 0
この回答へのお礼

>ソレは私のソースではないのですが…。
あれ・・申し訳ありませんでした;

>GetGlyphOutline()で取得したデータに4の倍数境界なんてありましたかね?
参考にしたサイトの中でそういう風に計算すると説明があったので
鵜呑みにしてしまったのですが、
まずかったのでしょうか。


これだけあれこれ教えて頂いていていつつも
頂いたソースすらまともに動かせず
どんどん頭の中がテンパってき誤爆レスまでしてすいません。

明日(というか今日)1日やってみて駄目だったら諦めて
別の方法を探す事にします。お騒がせして申し訳ありませんでした。
色々教えて下さって本当にありがとうございました。

お礼日時:2009/02/26 04:00

#3です。


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

この回答への補足

何かそんな気がします。

・画像の取得は頂いたサンプルと見比べ問題はありませんでした。
・描画座標は、描画の始点(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++;
}

補足日時:2009/02/25 23:57
    • good
    • 0
この回答へのお礼

// つづき 入りきれず省略多

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) {
// 描画
}

お礼日時:2009/02/26 00:09

以下の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で表わせる値をオーバーする可能性がある」ので注意。オーバーフローした場合、動作は不定。
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/05/26 20:38

ソースの例とか十分に付いている気がしないでもないですがせっかくなので。



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で埋めただけの構造体のアドレスを渡すとうまくいかないモノもありますので注意が必要です。
構造体の最初のメンバに「この構造体のサイズ」を設定するモノなど……。

この回答への補足

構造体の埋め方、ありがとうございます。
memset関数・・覚えておきます。使い方に注意も必要なのですね。

そして頂いた上のコードなのですが、
申し訳ないのですが、Image1の定義方法を教えて頂けないでしょうか;
BMP関係とまでは判ったのですが、インクルードすべきものが何なのかが未だわかりません;
描画はDirectXのテスクチャに頼り切ってしまっていて、申し訳ありません;

補足日時:2009/02/25 22:52
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/05/26 20:38

もしかして「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);
}
「GetGlyphOutline() ご利」の回答画像4
    • good
    • 0
この回答へのお礼

>もしかして「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で頂いたコードと合わせて描画まわりと座標の取得を見比べさせて頂いて
解決を目指してみます。

返答が遅れて申し訳ありません(色々やってみて動かせなくてすいません;)
ご回答ありがとうございます。

お礼日時:2009/02/25 15:13

「一文字目」というのは、違う文字でも、正しく取得できるのでしょうか。


なんとなく取得そのものは正常にできているように思えます。
gm.gmBlackBoxXをDWORD単位にするのを忘れていたりしませんか?

描画部分も含めたソースを全部載せたほうが的確な回答が得られるかもしれません。

この回答への補足

お返事遅くなりました。

>「一文字目」というのは、違う文字でも、正しく取得できるのでしょうか。
はい。
全角でも半角でも何でも1文字目は正しく描画されています。

>gm.gmBlackBoxXをDWORD単位
現在は
unsigned int(GM.gmBlackBoxX + (4-(GM.gmBlackBoxX%4))%4);
という定番らしい計算式を取り込んで計算しています。(4の倍数問題)

>ソースを全部
DirectXを利用してしまっていますが、
もう少し頑張って解決できなかったら考えさせて頂こうかと思います。

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

補足日時:2009/02/25 13:20
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/05/26 20:39

描画位置については…


http://marupeke296.com/WINT_GetGlyphOutline.html
に詳しく書かれてます。

http://www.greenwood.co.jp/~k-aki/article/ggo_tr …
環境によってはヘンな動作する…らしい。(なんという迷惑な…)

時間があれば簡単なサンプルでも作ってみるところなのですが…。
# 2つ目のURLでの指摘部分は無視したものになるでしょうけど。
睡眠時間足りてないのでちょっと無理です。

この回答への補足

>描画位置について
描画位置に関しては私もそのサイトを参考にさせて頂きました。
No1様の補足に書かせて頂きましたが、計算は正しくできていると思えます。

>環境によってはヘンな動作
やはり使わない方が良い関数という事なのですかね・・。
8日潰しただけに諦めるのがもったいないような、代替関数が無いか
探してはいるのですが・・。

>簡単なサンプル
切実にお願いしたく思えたりします・・。

以前1つのBYTEに[0] [2000] [4000] [6000]と1文字ずつ入れた時も
同様のせり上がり方をしたので
その時は無理やり表示する時に-45程し、並んでるかのようにはなったのですが、
x座標が激しくずれてループしたりして
1文字1つの宣言済みBYTEに入れるようにしました。

・1文字ずつバッファの書き込まれる位置が-45程手前にずれている
・x座標が不規則(同じ文字列ならば固定位置)に
 正常なのと大きくずれているのが混在してしまう

となっています。
別のインスタンスでも1文字ずつは正しく取得できるのですし、
ちょっと無茶をして1文字1インスタンスで確保しまくって上手く行くか
試してみようと思います。
ご助言ありがとうございます。

補足日時:2009/02/24 11:00
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/05/26 20:39

最後に触ったのがかなり前なので、あやふやですが…


# 手元の練習用ソースをgrepしたが…残っていなかった。

>参考元URL : ​http://marupeke296.com/DXGSmp_No5_Font.html
>上のURLの 「フォントビットマップ取得」 からの7行は
>「1文字あたりの画像取得に関してのみ」ほぼそのまま利用しています。

ptrで確保しているBYTE[]はその都度解放/確保しなおしているか?
必要とするバッファのサイズは文字ごとに変わります。
プロポーショナルピッチのフォントで「I」と「O」では幅が違いますし。
幅の違い以外に高さの違いもバッファサイズに影響したはずです。
「O」と「-」で取得できるグリフの高さが違ったはず。
# 描画位置などについてはGLYPHMETRICS構造体で受け取れる。
## 描画したい文字を一通りチェックて、取得したサイズのうち最大のものが収まるバッファを確保して使い回す。
## というのはアリでしょう。
## 確保/解放を繰り返した場合のオーバーヘッドや、メモリ領域のフラグメント回避にはよいかと。

グリフ取得時のGetGlyphOutline()の戻り値はチェックしているか?
エラー処理に必要かと。

とりあえず気になったのはこの2点くらいでしょうか。

# 念のためGLYPHMETRICS構造体は0x00で埋めてから渡す…とか。

この回答への補足

>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で埋めてから渡す…とか。
すみません、構造体の扱いに慣れておらず、
できれば埋め方のコードを教えて頂けませんでしょうか?
値のリセット方法がわからず、別の確認方法でかなり手間がかかったもので;

補足日時:2009/02/24 10:54
    • good
    • 0
この回答へのお礼

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

お礼日時:2010/05/26 20:39

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


このQ&Aを見た人がよく見るQ&A