2017-02-14 29 views
3

私の目標は、動的にHICONイメージにいくつかの任意のテキストを置くことです、私は次のコードを使用しています(実行時に。):GDIを使用して透明度を持つテキストを描画する方法は?

//Error checks are omitted for brevity 

//First create font 
LOGFONT lf = {0}; 
lf.lfHeight = -58; 
lf.lfWeight = FW_NORMAL; 
lf.lfOutPrecision = OUT_TT_PRECIS; //Use TrueType fonts for anti-alliasing 
lf.lfQuality = CLEARTYPE_QUALITY; 
lstrcpy(lf.lfFaceName, L"Segoe UI"); 

HFONT hFont = ::CreateFontIndirect(&lf); 


//HICON hIcon = original icon to use as a source 
//I'm using a large 256x256 pixel icon 
hIcon = (HICON)::LoadImage(theApp.m_hInstance, MAKEINTRESOURCE(IDI_ICON_GREEN_DIAMOND), IMAGE_ICON, 256, 256, LR_DEFAULTCOLOR); 

ICONINFO ii = {0}; 
::GetIconInfo(hIcon, &ii); 

BITMAP bm = {0}; 
::GetObject(ii.hbmColor, sizeof(bm), &bm); 
SIZE szBmp = {bm.bmWidth, bm.bmHeight}; 

HDC hDc = ::GetDC(hWnd); 
HDC hMemDC = ::CreateCompatibleDC(hDc); 

HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor); 
HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont); 

::SetBkMode(hMemDC, TRANSPARENT); 
::SetTextColor(hMemDC, RGB(255, 0, 0));  //Red text 

//Draw text 
//NOTE that DrawText API behaves in a similar way 
::TextOut(hMemDC, 0, 0, L"Hello", 5); 

::SelectObject(hMemDC, hOldFont); 
::SelectObject(hMemDC, hOldBmp); 


//We need a simple mask bitmap for the icon 
HBITMAP hBmpMsk = ::CreateBitmap(szBmp.cx, szBmp.cy, 1, 1, NULL); 

ICONINFO ii2 = {0}; 
ii2.fIcon = TRUE; 
ii2.hbmColor = ii.hbmColor; 
ii2.hbmMask = hBmpMsk; 

//Create updated icon 
HICON hIcon2 = ::CreateIconIndirect(&ii2); 


//Cleanup 
::DeleteObject(hBmpMsk); 
::DeleteDC(hMemDC); 
::ReleaseDC(hWnd, hDc); 
::DeleteObject(ii.hbmColor); 
::DeleteObject(ii.hbmMask); 

::DeleteObject(hFont); 

をして、私は(OnPaint()ハンドラからの私のウィンドウにアイコンを表示することができます私のような)ことが判明どのように見ることができる。

::DrawIconEx(dc.GetSafeHdc(), 0, 0, 
    hIcon2, 
    256, 256, NULL, 
    ::GetSysColorBrush(COLOR_BTNFACE), 
    DI_NORMAL); 

は、だからここに私が得るものです:

enter image description here

hIcon2でピクセル単位で起こっていることを見るには、上記のコードのをii.hbmColorと呼びました。ピクセルがそのメモリダンプにBGRAとしてエンコードされ、その各DWORDにおける第4バイトは、透明性を意味している

enter image description here

:私の言葉「こんにちは」がこのように見え示されることになった。得られた画素アレイ0 =透明、FF =不透明。しかし、この場合、TextOutは透明度を記入しないか、0として残します。これは「完全透過」と解釈されます。代わりに、それをあらかじめ色に掛けているようです。私は緑のダイヤモンドが始まる同じビットマップ、さらに下探し続ける場合は、画像のピクセルは透明性を持っているように見えること

注意が正しく設定バイト:

enter image description here

任意のアイデアはどのようにテキストを描画しますAPIはそれらの透過バイトを設定できますか?

編集:私は、次のGDI +の方法を試みたの下ようが示唆された。

HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor); 

Graphics grpx(hMemDC); 

RectF rcfTxt(0.0f, 0.0f, (REAL)szBmp.cx, (REAL)szBmp.cy); 
Font gdiFont(L"Segoe UI", 58.0f, FontStyleRegular, UnitPixel); 

SolidBrush gdiBrush(Color(255, 0, 0)); 

StringFormat gdiSF; 
gdiSF.SetAlignment(StringAlignmentNear); 
gdiSF.SetFormatFlags(StringFormatFlagsNoWrap); 
gdiSF.SetHotkeyPrefix(HotkeyPrefixNone); 

//The reason I was using GDI was because I was setting 
//spacing between letters using SetTextCharacterExtra() 
//Unfortunately with GDI+ this does not work! 
HDC hTmpDC = grpx.GetHDC(); 
::SetTextCharacterExtra(hTmpDC, -4); //This doesn't do anything! 
grpx.ReleaseHDC(hTmpDC); 

grpx.DrawString(L"Hello", 5, &gdiFont, rcfTxt, &gdiSF, &gdiBrush); 

::SelectObject(hMemDC, hOldBmp); 

と(私はGDIとSetTextCharacterExtraを使用できます)文字間隔を設定することができない以外は、ここで私は(少し得たものです)視認性の拡大:透明性

enter image description here

だから、明らかにまだ問題。

+0

GDIはアルファを理解しません。代わりにgdiplusを考慮する。 –

+0

@ JonathanPotter:ありがとう。 GDI +はアルファチャンネルをサポートする唯一の方法だと思われます。私が単純なGDIを使った理由は、['SetTextCharacterExtra'](https://msdn.microsoft.com/en-us/library/windows/desktop/dd145092(v = vs.85).aspx)を提供したためです。文字間隔を変更する機能。私はまだGDI +でそれを使用できるかどうか知っていますか? – c00000fd

答えて

1

Microsoft MVP Mike D Sutton hereの古いポストから引用しました。

あなたはそれが最初にデフォルトの「株式」オブジェクトが株式1 * 1 * 1のビットマップを含む、それに を選択しているDCを作成します。 DrawText()を呼び出すと、ビットマップ が既にDCに選択されているため、かなり多くのもの(1つのピクセルが とは別に1ピクセル)がクリップされても、 が描画されます。

ビットマップ (DDBまたはDIBSection)を作成し、DCに入力して を描画する必要があります。まず、あなたは あなたは のDrawTextを(使用しているためので、それは十分な大きさでテキストを表示したいので)あなたのビットマップのサイズを見つける最初のDCに再び呼び出す必要がありますがDT_CALCRECT フラグが含まれるものの

。これは単に何かを描くのではなく、 がテキストの大きさを測定し、それをRECTにダンプして コールを渡します。ここから、 のディメンションを使用してDIBSectionを作成し、DCに選択することができます。最後に、 にあるDIBSectionにテキストをレンダリングする 既存のDrawText()呼び出し(SetBkMode/Color()を使用することもできます) を実行します。あなたはそれを呼び出す方法の例が必要な場合は、その後(INDCをレンダリングするDCにある)この ような何かをしようと

HBITMAP CreateAlphaTextBitmap(LPCSTR inText, HFONT inFont, COLORREF inColour) { 
    int TextLength = (int)strlen(inText); 
    if (TextLength <= 0) return NULL; 

    // Create DC and select font into it 
    HDC hTextDC = CreateCompatibleDC(NULL); 
    HFONT hOldFont = (HFONT)SelectObject(hTextDC, inFont); 
    HBITMAP hMyDIB = NULL; 

    // Get text area 
    RECT TextArea = {0, 0, 0, 0}; 
    DrawText(hTextDC, inText, TextLength, &TextArea, DT_CALCRECT); 

    if ((TextArea.right > TextArea.left) && (TextArea.bottom > TextArea.top)) { 
     BITMAPINFOHEADER BMIH; 
     memset(&BMIH, 0x0, sizeof(BITMAPINFOHEADER)); 

     void *pvBits = NULL; 

     // Specify DIB setup 
     BMIH.biSize = sizeof(BMIH); 
     BMIH.biWidth = TextArea.right - TextArea.left; 
     BMIH.biHeight = TextArea.bottom - TextArea.top; 
     BMIH.biPlanes = 1; 
     BMIH.biBitCount = 32; 
     BMIH.biCompression = BI_RGB; 

     // Create and select DIB into DC 
     hMyDIB = CreateDIBSection(hTextDC, (LPBITMAPINFO)&BMIH, 0, (LPVOID*)&pvBits, NULL, 0); 
     HBITMAP hOldBMP = (HBITMAP)SelectObject(hTextDC, hMyDIB); 

     if (hOldBMP != NULL) { 
      // Set up DC properties 
      SetTextColor(hTextDC, 0x00FFFFFF); 
      SetBkColor(hTextDC, 0x00000000); 
      SetBkMode(hTextDC, OPAQUE); 

      // Draw text to buffer 
      DrawText(hTextDC, inText, TextLength, &TextArea, DT_NOCLIP); 

      BYTE* DataPtr = (BYTE*)pvBits; 
      BYTE FillR = GetRValue(inColour); 
      BYTE FillG = GetGValue(inColour); 
      BYTE FillB = GetBValue(inColour); 
      BYTE ThisA; 

      for (int LoopY = 0; LoopY < BMIH.biHeight; LoopY++) { 
       for (int LoopX = 0; LoopX < BMIH.biWidth; LoopX++) { 
        ThisA = *DataPtr; // Move alpha and pre-multiply with RGB 
        *DataPtr++ = (FillB * ThisA) >> 8; 
        *DataPtr++ = (FillG * ThisA) >> 8; 
        *DataPtr++ = (FillR * ThisA) >> 8; 
        *DataPtr++ = ThisA; // Set Alpha 
       } 
      } 

      // De-select bitmap 
      SelectObject(hTextDC, hOldBMP); 
     } 
    } 

    // De-select font and destroy temp DC 
    SelectObject(hTextDC, hOldFont); 
    DeleteDC(hTextDC); 

    // Return DIBSection 
    return hMyDIB; 
} 

は、これはかなりよくここで働いているようだ

void TestAlphaText(HDC inDC, int inX, int inY) { 
    const char *DemoText = "Hello World!\0"; 

    RECT TextArea = {0, 0, 0, 0}; 
    HFONT TempFont = CreateFont(50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial\0"); 
    HBITMAP MyBMP = CreateAlphaTextBitmap(DemoText, TempFont, 0xFF); 
    DeleteObject(TempFont); 

    if (MyBMP) { // Create temporary DC and select new Bitmap into it 
     HDC hTempDC = CreateCompatibleDC(inDC); 
     HBITMAP hOldBMP = (HBITMAP)SelectObject(hTempDC, MyBMP); 

     if (hOldBMP) { 
      BITMAP BMInf; // Get Bitmap image size 
      GetObject(MyBMP, sizeof(BITMAP), &BMInf); 

      // Fill blend function and blend new text to window 
      BLENDFUNCTION bf; 
      bf.BlendOp = AC_SRC_OVER; 
      bf.BlendFlags = 0; 
      bf.SourceConstantAlpha = 0x80; 
      bf.AlphaFormat = AC_SRC_ALPHA; 
      AlphaBlend(inDC, inX, inY, BMInf.bmWidth, BMInf.bmHeight, 
       hTempDC, 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); 

      // Clean up 
      SelectObject(hTempDC, hOldBMP); 
      DeleteObject(MyBMP); 
      DeleteDC(hTempDC); 
     } 
    } 
} 

すべてのクレジットカードとクレジットは、そのフォーラムの元のポスターに掲載されていますので、リンクを消すと有効です。

+0

本当に質問には答えません。彼がやっていることは(Googleの投稿で)、テキストに単色の背景をあらかじめ乗算しているようだ。私の背景は透明です。 – c00000fd

+0

@ c00000fd、そうだと思います。あらかじめ乗算されたアルファを使ってテキストを別のHBitmapにレンダリングする必要があります。次に、AlphaBlend(https://msdn.microsoft.com/en-us/library/windows/desktop/dd183351(v=vs.85).aspx)これを最終的なビットマップに貼り付けます。 – Ani

関連する問題