[BlueLeaf1336]> PROBLEMS> FontStudy>

フォント勉強会その4

historyTOP

2009/12/08:作成

ここまでのおさらいTOP

前回までに、GetGlyphOutlineでアンチエイリアス的なデータを取得できることを確かめました。ここで「的」と書いたのはデータの中身を見たらそうなってたってことで、実際にそれを描画するところまではいけませんでした。

それとは別に、CreateDIBSectionを使って、手作業で作成したアンチエイリアスデータを渡せばそれなりに描画してくれることも確かめました。

いよいよ合体です。GetGlyphOutlineでアンチエイリアスデータを作成して、CreateDIBSectionに渡してビットマップデータに変換です。ここでは、Graphics.TBitmapに描画しました。ソースはこんな感じ。

できるだけ、後半は触らないでいいようにしましたが、まだしきれてません。残念。

//-----------------------------------------------------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
    LMat2: TMat2;
    LMetrics: TGlyphMetrics;
    LChar: String;
    LFormat: Cardinal;
    LSize: Cardinal;
var
    LPoint: TPoint;
    LWidth: Integer;
    LHeight: Integer;
    LDC: HDC;
var
    LDib: HBITMAP;
    LDibInfo: PBitmapInfo;
    LBitsPtr: PByte;
    LRefDC: HDC;
    i: Integer;
    //  多分宣言するだけでそれなりの中身になる(初期値がある。んだと思う)
    LSystemPalette: array[Byte] of TPaletteEntry;
    //  バイト配列
    LBuf: array of Byte;
begin
    LPoint := Point(0, 0);
    LChar := Edit1.Text;
    LDC := FBitmap.Canvas.Handle;

    //  構造体初期化
    FillChar(LMat2, SizeOf(LMat2), 0);
    LMat2.eM11.Value := 1;
    LMat2.eM22.Value := 1;
    FillChar(LMetrics, SizeOf(LMetrics), 0);

    //  出力フォーマット
    //LFormat := GGO_BITMAP;
    //LFormat := GGO_GRAY2_BITMAP;
    //LFormat := GGO_GRAY4_BITMAP;
    LFormat := GGO_GRAY8_BITMAP;

    //  GetGlyphOutline
    LSize := GetGlyphOutline(LDC, OrdEx(LChar), LFormat, LMetrics, 0, nil, LMat2);
    SetLength(LBuf, LSize);
    LSize := GetGlyphOutline(LDC, OrdEx(LChar), LFormat, LMetrics, LSize, LBuf, LMat2);

    //  画像のサイズを求める
    LWidth  := LSize div LMetrics.gmBlackBoxY;
    LHeight := LMetrics.gmBlackBoxY;

    //  ■■■■ 出力先のビットマップのサイズを設定
    FBitmap.Width := LWidth;
    FBitmap.Height := LHeight;
    //  ここで改めてHandle代入しないと動きが変。
    LDC := FBitmap.Canvas.Handle;

    //  ■ 1 ■ 前準備

    //  ビットマップ情報のデータ構造体に必要なメモリを確保
    GetMem(LDibInfo, SizeOf(TBitMapInfo) + 256 * SizeOf(TRGBQuad));

    //  TPaletteEntry と TRGBQuad の間の差を調整(理解する気なし)
    for i := Low(Byte) to High(Byte) do
    begin
        LDibInfo^.bmiColors[i].rgbBlue      := LSystemPalette[i].peBlue;
        LDibInfo^.bmiColors[i].rgbRed       := LSystemPalette[i].peRed;
        LDibInfo^.bmiColors[i].rgbGreen     := LSystemPalette[i].peGreen;
        LDibInfo^.bmiColors[i].rgbReserved  := 0;
    end;

    //  ビットマップ情報の初期化
    LDibInfo^.bmiHeader.biWidth         := LWidth;      //  幅
    LDibInfo^.bmiHeader.biHeight        := - LHeight;   //  高さ(向き)
    LDibInfo^.bmiHeader.biPlanes        := 1;
    LDibInfo^.bmiHeader.biBitCount      := 8;           //  2^8 = 256色
    LDibInfo^.bmiHeader.biCompression   := BI_RGB;      //  圧縮なし
    LDibInfo^.bmiHeader.biSizeImage     := 0;           //  Windows任せ
    LDibInfo^.bmiHeader.biXPelsPerMeter := 0;
    LDibInfo^.bmiHeader.biYPelsPerMeter := 0;
    LDibInfo^.bmiHeader.biClrUsed       := 0;
    LDibInfo^.bmiHeader.biClrImportant  := 0;
    LDibInfo^.bmiHeader.biSize          := SizeOf(TBitMapInfoHeader);

    //  DIBを作成。ビットマップ情報も初期化
    LRefDC := CreateCompatibleDC(0);
    LDib := CreateDIBSection(
                LRefDC,             //  [in]参考にするデバイスコンテキスト
                LDibInfo^,          //  [in]今から作るビットマップの情報
                DIB_RGB_COLORS,     //  [in]TBitMapInfo.bmiColors[]はRGB値そのもの
                Pointer(LBitsPtr),  //  [out]作成されたビットマップビットのポインタ
                0, 0);              //  [in]ゼロならWindows任せ
    DeleteDC(LRefDC);

    //  ■ 2 ■ データ作成
    Move(LBuf[0], LBitsPtr^, Length(LBuf));

    //  ■ 3 ■ 描画
    SetDIBitsToDevice(
            LDC, LPoint.X, LPoint.Y, LWidth, LHeight,   //  描画位置とサイズ
            0, 0, 0, LHeight,                           //  SrcX, SrcY, 走査開始行と行数
            LBitsPtr, LDibInfo^,                        //  ビットマップの内容
            DIB_RGB_COLORS);                            //  CreateDIBSection と同じもの

    //  ■ 4 ■ 後始末
    DeleteObject(LDib);
    FreeMem(LDibInfo, SizeOf(TBitMapInfo) + 256 * SizeOf(TRGBQuad));

    //  ■■■■ 画面再描画
    Self.Repaint();
end;

念のためネット上にバックアップ
20091208_1_FontStudy_src.zip(234,248bytes)

実行結果はこんな感じです。

見たとおり変です。ちゃんと縁がわしゃわしゃしててますが、色が悪い。原因もわかってます。GetGlyphOutlineが出力するのはグレースケールなのに、CreateDIBSectionは256色カラーのつもりで受け取ってるからそりゃおかしくならない方がおかしい。

あ、思い出しましたが、上のソースコードでは、GetGlyphOutlineをGGO_BITMAP (モノクロモード)で実行してはだめです。どうなるかは試してませんが、そもそもデータ構造が違います。GGO_BITMAPは1ピクセル1ビットでデータが出てくるのに対して、GGO_GRAYn_BITMAPは、1ピクセル1バイトです。

もう少し落ち着いたら1つの関数にでもまとめたいところですが、今はおいときます。

ところで前回起きていたWindowsがナニカの再描画を行うたびにプログラムで描画した文字の色がごろごろ変わるのは、なぜか解消してます。もう本当によくわからないです。

EOFTOP