这对我的朋友来说,是一个很长的...
当我尝试在分层窗口中渲染文本时,我得到了一些非常奇怪的行为。
奇怪的是,对于某些字体/字体样式/字体大小的组合,GDI +会更改渲染方法。对于Tahoma-Bold字体 8.49和16.49(像素单位)之间的,包括“失败”。对于其他字体和样式,我会以不同的尺寸“失败”。
为了清楚起见,我已经提供了一个完整的可执行示例。要使用的两个关键参数在第23行:
Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work!
#define USE_LAYERED_WINDOW // or just comment this line out [to use a regular window], and everything will work!
当使用分层窗口和完全不透明度时,字体在背景中绘制一个透明的“洞”。但是,如果我为文本颜色添加轻微的透明度(alpha-channel = 254),则字体会变得不透明。或者,如果我使用常规(非分层)窗口,则字体呈现不透明。 这里发生了什么?
但即使没有分层/透明问题,很明显这里发生了一些奇怪的事情。字体大小为8.49 - 16.48,渲染像素完美,其他字体质量模糊,特别是小字体。因此,系统似乎采用不同的方法来渲染这些中等大小。 有人可以对此有所了解,我怎么可能渲染字体大小为8.0像素而没有上面的模糊?我已经尝试了SetTextRenderingHint()
和SetTextContrast()
的各种设置但是对于8号字体来说,没有一个看起来很清脆。我试过了Tahoma&只有Arial ......
问题1:
我想使用纯GDI +进行离屏绘图,但我无法通过简单地创建Bitmap
& Graphics
个对象。我仍然不得不使用旧的GDI东西来创建DC并选择HBitmap。我怎样才能在GDI +中完成所有工作?
问题2(仅限极客): 我也尝试在古老的GDI中绘制字体,但是我得到了一些更奇怪的效果:(1)在分层窗口中,文本变得透明,但是在添加剂中方式。 (所以如果背后的窗户是黑暗的,那么红色的文字看起来会很好但是如果背后的窗户是白色的,那么文字完全消失了!)此外,如果我用半透明的方形填充我自己的窗户,那么表现就像预期的那样。 (如果背后的窗口是黑色的话,红色正方形会变成深红色,并且正方形会在白色窗口上变成浅红色)。我可以在一个分层窗口中同时观察这两种行为。并且(2)作为一个非常不受欢迎的奖励,所绘制的文字失去了它的命中测试并变得无法点击? 有任何解释吗?
如果您已经阅读了这篇文章,感谢您的持久,感谢您的回答!
// Create as a console application project
// + Unicode charset
// + Precompiled headers off
// + make sure to add linker input: gdiplus.lib
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
// Standard and GDI+ stuffstuff
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>
#include <cassert>
#include <Gdiplus.h>
using namespace Gdiplus;
GdiplusStartupInput g_oGdiPlusStartupInput;
ULONG_PTR g_pGdiPlusToken = NULL;
// #*#*#*#*#*#*#*#*# LINES TO CHANGE ---------->---------->---------->
Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work!
#define USE_LAYERED_WINDOW // or just comment this line out [to use a regular window], and everything will work!
// Forward declarations
void RegWndClass();
LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam );
void CreateWindows();
void Draw();
void MsgLoop();
// Other Globals
ATOM g_iWndClass = 0;
HWND g_hWndGdiPlus = NULL;
HWND g_hWndGdi = NULL;
const wchar_t* g_pWndClass = L"TST";
int g_iWidth = 200;
int g_iHeight = 200;
// Main entry-point
int _tmain( int argc, _TCHAR* argv[] )
{
GdiplusStartup( &g_pGdiPlusToken, &g_oGdiPlusStartupInput, NULL );
RegWndClass();
CreateWindows();
Draw();
MsgLoop();
::UnregisterClass( g_pWndClass, NULL );
::Sleep( 500 );
GdiplusShutdown( g_pGdiPlusToken );
return 0;
} // _tmain
void CreateWindows()
{
#ifdef USE_LAYERED_WINDOW
// The key trick is to create a window with style WS_EX_LAYERED, but WITHOUT any subsequent calls to SetLayeredWindowAttributes()
// This gives us a magic window that must be updated with UpdateLayeredWindow() ( and it does NOT recieve any WM_PAINT messages )
// as brilliantly described in: http://alexkr.com/source-code/50/layered-windows-and-updatelayeredwindow/
g_hWndGdiPlus = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL );
#else
g_hWndGdiPlus = ::CreateWindowEx( 0, g_pWndClass, L"", WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL );
#endif
//g_hWndGdi = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 720, 500, 200, 200, NULL, NULL, NULL, NULL );
} // CreateWindows
void Draw()
{
// Init GDI+ surface
HDC hOff = ::CreateCompatibleDC( NULL );
Bitmap oDaBigOne( g_iWidth, g_iHeight, PixelFormat32bppARGB );
HBITMAP hBMit = NULL;
Color oCol( 0, 0, 0, 0 );
oDaBigOne.GetHBITMAP( oCol, &hBMit );
HGDIOBJ hSave = ::SelectObject( hOff, hBMit );
#ifdef USE_LAYERED_WINDOW
Graphics oGraph( hOff );
#else
Graphics oGraph( g_hWndGdiPlus );
#endif
oGraph.Clear( Color( 255, 55, 155, 255 ) );
// Draw text
oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
oGraph.SetTextContrast( 0xffffffff );
oGraph.SetCompositingMode( CompositingModeSourceOver );
oGraph.SetCompositingQuality( CompositingQualityHighQuality );
oGraph.SetPixelOffsetMode( PixelOffsetModeHighQuality );
const FontFamily oFamily( L"Tahoma", NULL );
#if 1 // Use bold
Font oF600( &oFamily, 6.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF800( &oFamily, 8.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF848( &oFamily, 8.48, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF849( &oFamily, 8.49, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1200( &oFamily, 12.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1500( &oFamily, 15.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1648( &oFamily, 16.48, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1649( &oFamily, 16.49, FontStyle::FontStyleBold, Unit::UnitPixel );
#else // Use regular
Font oF600( &oFamily, 6.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF800( &oFamily, 8.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF848( &oFamily, 8.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF849( &oFamily, 8.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1200( &oFamily, 12.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1500( &oFamily, 15.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1648( &oFamily, 16.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1649( &oFamily, 16.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
#endif
assert( oF600.GetLastStatus() == Ok ); // Make sure font is OK
SolidBrush oBrush( g_oTextColor );
double dy = 1.0;
oGraph.DrawString( L"Size 6.00", -1, &oF600, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 8.00", -1, &oF800, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 8.48", -1, &oF848, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 8.49", -1, &oF849, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 12.00", -1, &oF1200, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 15.00", -1, &oF1500, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 16.48", -1, &oF1648, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 16.49", -1, &oF1649, PointF( 30.0, dy += 18.0 ), &oBrush );
#ifndef USE_LAYERED_WINDOW
return;
#endif
// Do da layered window magic stuff
BLENDFUNCTION oBF = { 0 };
oBF.BlendOp = AC_SRC_OVER;
oBF.BlendFlags = 0;
oBF.SourceConstantAlpha = 255;
oBF.AlphaFormat = AC_SRC_ALPHA;
SIZE oSize = { 0 };
oSize.cx = g_iWidth;
oSize.cy = g_iHeight;
POINT oPTZero = { 0 };
RECT oRect = { 0 };
::GetWindowRect( g_hWndGdiPlus, &oRect );
POINT oPTWnd = { 0 };
oPTWnd.x = oRect.left;
oPTWnd.y = oRect.top;
//HDC hDC = oGraph.GetHDC();
BOOL bOK = ::UpdateLayeredWindow( g_hWndGdiPlus,
NULL, //HDC hdcDst,
&oPTWnd, // POINT &oPtNull,
&oSize, // SIZE *psize,
hOff, // HDC hdcSrc,
&oPTZero, // POINT *pptSrc,
RGB(255,255,255), // COLORREF crKey,
&oBF, // BLENDFUNCTION *pblend,
ULW_ALPHA // DWORD dwFlags
);
} // Draw
void MsgLoop()
{
::SetTimer( g_hWndGdiPlus, 0, 19999, NULL ); // Self-destruct timer
MSG msg = { 0 };
while ( ::GetMessage( &msg, NULL, 0, 0 ) )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
} // MsgLoop
void RegWndClass()
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 8; // 8 bytes, to allow for 64-bit architecture
wcex.hInstance = NULL; // CHECK
wcex.hIcon = NULL;
wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)NULL_BRUSH; // CHECK
wcex.lpszMenuName = NULL;
wcex.lpszClassName = g_pWndClass;
wcex.hIconSm = NULL;
g_iWndClass = ::RegisterClassEx(&wcex);
} // RegWndClass
LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
{
switch( uiMsg )
{
case WM_TIMER:
{
std::wstring s;
std::wcout << L"Let´s quit" ;
::PostQuitMessage( 0 );
return 0;
}
case WM_PAINT:
Draw();
break;
default:
{
return DefWindowProc( hWnd, uiMsg, wParam, lParam );
}
}
return DefWindowProc( hWnd, uiMsg, wParam, lParam );
} // WndProc
[编辑]问题解决了! 根据{{3}}出色的建议,下面的代码。 感谢他和他的巨大感谢。我真的很感激。
所有修改都标有//#MOD
// Create as a console application project
// + Unicode charset
// + Precompiled headers off
// + make sure to add linker input: gdiplus.lib
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
// Standard stuff
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>
#include <cassert>
// GDI+ stuff
#include <Gdiplus.h>
using namespace Gdiplus;
GdiplusStartupInput g_oGdiPlusStartupInput;
ULONG_PTR g_pGdiPlusToken = NULL;
// #*#*#*#*#*#*#*#*# LINES TO CHANGE ---------->---------->---------->
Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work!
#define USE_LAYERED_WINDOW // or just omment this line [to use a regular window], and everything will work!
// Forward declarations
void RegWndClass();
LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam );
void CreateWindows();
void Draw();
void MsgLoop();
// Other Globals
ATOM g_iWndClass = 0;
HWND g_hWndGdiPlus = NULL;
HWND g_hWndGdi = NULL;
const wchar_t* g_pWndClass = L"TST";
int g_iWidth = 200;
int g_iHeight = 200;
// Main entry-point
int _tmain( int argc, _TCHAR* argv[] )
{
GdiplusStartup( &g_pGdiPlusToken, &g_oGdiPlusStartupInput, NULL );
RegWndClass();
CreateWindows();
Draw();
MsgLoop();
::UnregisterClass( g_pWndClass, NULL );
::Sleep( 500 );
GdiplusShutdown( g_pGdiPlusToken );
return 0;
} // _tmain
void CreateWindows()
{
#ifdef USE_LAYERED_WINDOW
// The key trick is to create a window with style WS_EX_LAYERED, but WITHOUT any subsequent calls to SetLayeredWindowAttributes()
// This gives us a magic window that must be updated with UpdateLayeredWindow() ( and it does NOT recieve any WM_PAINT messages )
// as brilliantly described in: http://alexkr.com/source-code/50/layered-windows-and-updatelayeredwindow/
g_hWndGdiPlus = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL );
#else
g_hWndGdiPlus = ::CreateWindowEx( 0, g_pWndClass, L"", WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL );
#endif
//g_hWndGdi = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 720, 500, 200, 200, NULL, NULL, NULL, NULL );
} // CreateWindows
void Draw()
{
// Init GDI+ surface
HDC hOff = ::CreateCompatibleDC( NULL );
Bitmap oDaBigOne( g_iWidth, g_iHeight, PixelFormat32bppARGB );
HBITMAP hBMit = NULL;
Color oCol( 0, 0, 0, 0 );
// oDaBigOne.GetHBITMAP( oCol, &hBMit ); //#MOD
// HGDIOBJ hSave = ::SelectObject( hOff, hBMit ); //#MOD
{ // Limit oGraph scope //#MOD
#ifdef USE_LAYERED_WINDOW
//Graphics oGraph( hOff ); //#MOD
Graphics oGraph( &oDaBigOne ); //#MOD
#else
Graphics oGraph( g_hWndGdiPlus );
#endif
oGraph.Clear( Color( 255, 55, 155, 255 ) );
// Draw text
oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
oGraph.SetCompositingMode( CompositingModeSourceOver );
oGraph.SetCompositingQuality( CompositingQualityHighQuality );
oGraph.SetPixelOffsetMode( PixelOffsetModeHighQuality );
const FontFamily oFamily( L"Tahoma", NULL );
#if 1 // Use bold
Font oF600( &oFamily, 6.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF848( &oFamily, 8.48, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF849( &oFamily, 8.49, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1200( &oFamily, 12.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1500( &oFamily, 15.00, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1648( &oFamily, 16.48, FontStyle::FontStyleBold, Unit::UnitPixel );
Font oF1649( &oFamily, 16.49, FontStyle::FontStyleBold, Unit::UnitPixel );
#else // Use regular
Font oF600( &oFamily, 6.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF848( &oFamily, 8.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF849( &oFamily, 8.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1200( &oFamily, 12.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1500( &oFamily, 15.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1648( &oFamily, 16.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
Font oF1649( &oFamily, 16.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
#endif
assert( oF600.GetLastStatus() == Ok ); // Make sure font is OK
SolidBrush oBrush( g_oTextColor );
double dy = 10.0;
oGraph.DrawString( L"Size 6.00", -1, &oF600, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 8.48", -1, &oF848, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 8.49", -1, &oF849, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 12.00", -1, &oF1200, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 15.00", -1, &oF1500, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 16.48", -1, &oF1648, PointF( 30.0, dy += 18.0 ), &oBrush );
oGraph.DrawString( L"Size 16.49", -1, &oF1649, PointF( 30.0, dy += 18.0 ), &oBrush );
#ifndef USE_LAYERED_WINDOW
return;
#endif
} // Limit oGraph scope //#MOD
// Do da layered window magic stuff
BLENDFUNCTION oBF = { 0 };
oBF.BlendOp = AC_SRC_OVER;
oBF.BlendFlags = 0;
oBF.SourceConstantAlpha = 255;
oBF.AlphaFormat = AC_SRC_ALPHA;
SIZE oSize = { 0 };
oSize.cx = g_iWidth;
oSize.cy = g_iHeight;
POINT oPTZero = { 0 };
RECT oRect = { 0 };
::GetWindowRect( g_hWndGdiPlus, &oRect );
POINT oPTWnd = { 0 };
oPTWnd.x = oRect.left;
oPTWnd.y = oRect.top;
oDaBigOne.GetHBITMAP( oCol, &hBMit ); //#MOD
HGDIOBJ hSave = ::SelectObject( hOff, hBMit ); //#MOD
//HDC hDC = oGraph.GetHDC();
BOOL bOK = ::UpdateLayeredWindow( g_hWndGdiPlus,
NULL, //HDC hdcDst,
&oPTWnd, // POINT &oPtNull,
&oSize, // SIZE *psize,
hOff, // HDC hdcSrc,
&oPTZero, // POINT *pptSrc,
RGB(255,255,255), // COLORREF crKey,
&oBF, // BLENDFUNCTION *pblend,
ULW_ALPHA // DWORD dwFlags
);
} // Draw
void MsgLoop()
{
::SetTimer( g_hWndGdiPlus, 0, 19999, NULL ); // Self-destruct timer
MSG msg = { 0 };
while ( ::GetMessage( &msg, NULL, 0, 0 ) )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
} // MsgLoop
void RegWndClass()
{
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 8; // 8 bytes, to allow for 64-bit architecture
wcex.hInstance = NULL; // CHECK
wcex.hIcon = NULL;
wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)NULL_BRUSH; // CHECK
wcex.lpszMenuName = NULL;
wcex.lpszClassName = g_pWndClass;
wcex.hIconSm = NULL;
g_iWndClass = ::RegisterClassEx(&wcex);
} // RegWndClass
LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
{
switch( uiMsg )
{
case WM_TIMER:
{
std::wstring s;
std::wcout << L"Let´s quit" ;
::PostQuitMessage( 0 );
return 0;
}
case WM_PAINT:
Draw();
break;
default:
{
return DefWindowProc( hWnd, uiMsg, wParam, lParam );
}
}
return DefWindowProc( hWnd, uiMsg, wParam, lParam );
} // WndProc
答案 0 :(得分:6)
我认为问题在于GDI(没有+)不能很好地支持alpha透明度。充其量,它保持alpha通道不受影响。
当您使用具有Alpha通道的选定位图的HDC构建Graphics对象时......事情变得非常糟糕。我的猜测是GDI +字体栅格化决定了基于大量参数使用哪种方法进行渲染;然后,如果GDI支持这种方法,它将被使用(并忽略alpha通道);如果GDI不支持渲染方法,它将回退到逐像素渲染或类似渲染,并且alpha通道将被正确使用。
因此,要获得正确的结果,您不应使用HDC修改Alpha通道。请尝试以下更改:
使用位图创建Graphics对象,而不是HDC:
Graphics oGraph( &oDaBigOne );
仅在完成渲染后才将位图选择到HDC hOff中。为了确保Graphics对象被销毁更好,用{...}限制其范围。
<强> [编辑] 强>
在新代码之后,解决方案很简单:不仅应该在绘图之后将调用移动到SelectObject(),还要调用GetBitmap()。也就是说,这两个函数应该在调用之前:UpdateLayeredWindow():
oDaBigOne.GetHBITMAP( oCol, &hBMit );
HGDIOBJ hSave = ::SelectObject( hOff, hBMit );
答案 1 :(得分:2)
我认为,昨天我找到了一个(部分)解决方案,这可能比rodrigo建议的更容易实现:你可以简单地在{{StringFormatFlags::StringFormatFlagsBypassGDI
中指定StringFormat
作为格式标志1}} - 你传递给DrawString
的实例,瞧:一切都是使用支持alpha的字体渲染器绘制的。这解决了alpha通道问题,至少......
答案 2 :(得分:1)
我暂时无法找到对这种奇怪行为的解释。但是,我确实发现使用默认渲染值可以使用某些字体获得更好的结果,请尝试使用以下设置进行Arial:
oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
oGraph.SetPixelOffsetMode( PixelOffsetModeDefault );
oGraph.SetCompositingMode( CompositingModeSourceOver );
oGraph.SetCompositingQuality( CompositingQualityDefault );
答案 3 :(得分:0)
尝试将PixelFormat32bppARGB
替换为PixelFormat32bppPARGB
。 BLENDFUNCTION
结构的文档声明它需要在源中预乘alpha。