[英]Drawing asian text with GDI+ gives transparent characters on a layered window
我有一個分層的窗口,可以使用WS_EX_LAYERED
擴展樣式和UpdateLayeredWindow
函數來創建自己。
然后,我使用GDI +庫Graphics :: DrawString方法在其中繪制一些文本。
結果是: 分層窗口的屏幕截圖 。
如您所見,日文,韓文和中文字符是完全透明的。 它們甚至使窗口的白色背景透明,而根本不透明。
僅當禁用“ 桌面合成” (Aero主題)時,才會在Windows Vista和Windows 7上出現此問題。
在Windows 10上它可以正常工作,因為始終在其中啟用了“桌面合成”。
為什么只有東亞字符會產生這種奇怪的效果?
以及如何解決?
我沒有要測試的Windows 7機器,所以我不知道alpha通道是否是真正的問題,但是假設它是真實的,您可以通過在編寫了Windows 7之后將alpha通道設置回正確的狀態來解決它。越野車文字:
enum { WIDTH = 255 * 3, HEIGHT = 25 };
#define CalcStride(w, bpp) ( ((((w) * (bpp)) + 31) & ~31) >> 3 )
#define PMC(c, a) ( (c) = ((int)(c) * (a) / 255) )
#define PM(q) PMC( (q).rgbRed, (q).rgbReserved), PMC( (q).rgbGreen, (q).rgbReserved), PMC( (q).rgbBlue, (q).rgbReserved)
RGBQUAD* GetPxPtr32(void*pBits, UINT x, UINT y)
{
return ((RGBQUAD*) ( ((char*)pBits) + (y * CalcStride(WIDTH, 32)) )) + x;
}
void SaveAlpha32(void*pBits, BYTE*buf)
{
for (UINT x = 0; x < WIDTH; ++x)
for (UINT y = 0; y < HEIGHT; ++y)
buf[(y * WIDTH) + x] = GetPxPtr32(pBits, x, y)->rgbReserved;
}
void RestoreAlpha32(void*pBits, const BYTE*buf)
{
for (UINT x = 0; x < WIDTH; ++x)
for (UINT y = 0; y < HEIGHT; ++y)
GetPxPtr32(pBits, x, y)->rgbReserved = buf[(y * WIDTH) + x];
}
void Draw(HDC hDC, HBITMAP hBM, void*pBits, UINT w, UINT h, bool isDwmActive)
{
// Fill with white and a silly gradient alpha channel:
for (UINT y = 0; y < h; ++y)
for (UINT x = 0; x < w; ++x)
(*(UINT32*)GetPxPtr32(pBits, x, y)) = 0xffffffff, GetPxPtr32(pBits, x, y)->rgbReserved = max(42, x % 255);
BYTE *alphas = isDwmActive ? 0 : (BYTE*) LocalAlloc(LPTR, sizeof(BYTE) * w * h), fillWithRed = true;
if (!isDwmActive) SaveAlpha32(pBits, alphas);
HGDIOBJ hBmOld = SelectObject(hDC, hBM);
RECT r = { 0, 0, WIDTH, HEIGHT };
int cbk = SetBkColor(hDC, RGB(255, 0, 0));
if (fillWithRed) ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &r, NULL, 0, NULL);
int ctx = SetTextColor(hDC, RGB(0, 0, 0));
int mode = SetBkMode(hDC, TRANSPARENT);
DrawText(hDC, TEXT("Hello World Hello World Hello World Hello World Hello World"), -1, &r, DT_SINGLELINE|DT_VCENTER|DT_CENTER); // Plain GDI always destroys the alpha
SetBkMode(hDC, mode), SetBkColor(hDC, cbk), SetTextColor(hDC, ctx);
SelectObject(hDC, hBmOld), GdiFlush();
if (!isDwmActive) RestoreAlpha32(pBits, alphas), LocalFree(alphas);
for (UINT y = 0; y < h; ++y) for (UINT x = 0; x < w; ++x) PM(*GetPxPtr32(pBits, x, y));
}
int main()
{
const INT w = WIDTH, h = HEIGHT, bpp = 32, x = 222, y = 222;
HWND hWnd = CreateWindowEx(WS_EX_LAYERED|WS_EX_TOPMOST, WC_STATIC, 0, WS_VISIBLE|WS_POPUP, x, y, WIDTH, HEIGHT, 0, 0, 0, 0);
SetWindowLong(hWnd, GWLP_WNDPROC, (LONG_PTR) DefWindowProc); // HACK
BITMAPINFO bi;
ZeroMemory(&bi, sizeof(bi));
BITMAPINFOHEADER&bih = bi.bmiHeader;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = w, bih.biHeight = -h;
bih.biPlanes = 1, bih.biBitCount = bpp;
bih.biCompression = BI_RGB;
void*bits;
HBITMAP hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &bits, NULL, 0);
HDC hDCScreen = GetDC(NULL), hDC = CreateCompatibleDC(hDCScreen);
Draw(hDC, hBmp, bits, w, h, false);
HGDIOBJ hBmOld = SelectObject(hDC, hBmp);
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER, blend.AlphaFormat = AC_SRC_ALPHA, blend.SourceConstantAlpha = 255;
POINT location = { x, y }, srcpt = { 0, 0 };
SIZE szWnd = { w, h };
UpdateLayeredWindow(hWnd, hDCScreen, &location, &szWnd, hDC, &srcpt, 0, &blend, ULW_ALPHA);
SelectObject(hDC, hBmOld), DeleteObject(hBmp);
DeleteDC(hDC), ReleaseDC(NULL, hDCScreen);
struct Closer { Closer(HWND h) { SetTimer(h, 1, 1000 * 11, TP); } static void CALLBACK TP(HWND h,UINT,UINT_PTR,DWORD) { ExitProcess(666); } } closer(hWnd); // HACK
for (MSG msg; GetMessage(&msg, 0, 0, 0); ) DispatchMessage(&msg);
return 666;
}
如果您不關心沒有平台更新的Vista,則可以嘗試使用Direct2D代替GDI +。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.