GDI对32位alpha位图仅能进行COLORONCOLOR的缩放,也就是直接丢弃像素,不能实现HALFTONE缩放,也就没办法进行超采样除锯齿。
如果觉得GDI+比较慢,很难实现特殊效果的话,可以使用Direct2D/DirectWrite/WIC。
可以使用Windows 98加入的支持Alpha通道的三个API绘制复杂图形
GdiGradientFill:向HDC进行矩形或三角形填充,三角形填充类似Direct3D或OpenGL
GdiTransparentBlt:HDC之间进行抠色传送
GdiAlphaBlend:与其它HDC之间进行Alpha混合
大部分情况下并不需要GdiTransparentBlt,而比较多使用GdiGradientFill和GdiAlphaBlend。
注意颜色格式为预乘alpha的32位色,即在提交颜色之前要进行预乘:
red = red * alpha / 0xff;
green = green * alpha / 0xff;
blue = blue * alpha / 0xff;
GdiGradientFill比较特殊,颜色范围为0x0000到0xff00:
red = red * alpha / 0xff00;
green = green * alpha / 0xff00;
blue = blue * alpha / 0xff00;
这几个函数比较慢,为了提高效率,建议只在内存位图中进行GdiGradientFill和GdiAlphaBlend,最后一次BitBlt到设备。
Windows NT还支持以下两个函数:
MaskBlt:带掩码的传送
PlgBlt:平行四边形传送,可以旋转和挤压,允许有掩码,但有掩码的情况下不能旋转和挤压。
如果以上函数全部使用,则程序只能支持Windows 2000以上操作系统。
所有操作系统都支持的传送:
BitBlt:按位传送
StretchBlt:带伸缩的传送
PatBlt:画刷传送
GdiGradientFill和GdiAlphaBlend示例代码:
case WM_PAINT:
{
// 开始绘制
hdc = BeginPaint(hWnd, &ps);
// 得到客户区大小
RECT rc;
GetClientRect(hWnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
// 创建目标缓冲位图和位图设备
HBITMAP htargetbmp = CreateCompatibleBitmap(hdc, width, height);
HDC htargetdc = CreateCompatibleDC(hdc);
SelectObject(htargetdc, htargetbmp);
// 填充底色,此处也可以使用FillRect
TRIVERTEX vrectfill[] = {
{ 0, 0, 0xff00, 0x0000, 0x0000, 0xff00 },
{ width, height, 0x0000, 0xff00, 0x0000, 0xff00 },
};
GRADIENT_RECT grrectfill[] = { { 0, 1 } };
GdiGradientFill(htargetdc, vrectfill, 2, grrectfill, 1, GRADIENT_FILL_RECT_H);
// 创建包含alpha通道的位图和位图设备
// 我们要在这上边绘制一个透明的圆形
HBITMAP halphabmp = CreateBitmap(width, height, 1, 32, NULL);
HDC halphadc = CreateCompatibleDC(hdc);
SelectObject(halphadc, halphabmp);
// 透明圆形的颜色和位置参数
// 颜色范围从0x0000到0xff00
COLOR16 circle_red = 0, circle_green = 0, circle_blue = 0xff00, circle_alpha = 0x7f00;
int circle_x = 100, circle_y = 100, circle_rad = 50;
// 使用三角形绘制圆形
// 进行alpha预乘
circle_red = circle_red * circle_alpha / 0xff00;
circle_green = circle_green * circle_alpha / 0xff00;
circle_blue = circle_blue * circle_alpha / 0xff00;
// 构造圆形的顶点:一个圆心和360个顶点
TRIVERTEX vtri[361] = { {
circle_x, circle_y, circle_red, circle_green, circle_blue, circle_alpha
} };
for (int i = 0; i < 360; i++)
{
vtri[i + 1].x = circle_x + circle_rad * cos(i / 360.0f * 2 * acos(-1));
vtri[i + 1].y = circle_y + circle_rad * sin(i / 360.0f * 2 * acos(-1));
vtri[i + 1].Red = circle_red;
vtri[i + 1].Green = circle_green;
vtri[i + 1].Blue = circle_blue;
vtri[i + 1].Alpha = circle_alpha;
}
// 构造圆形的三角面:圆心和两个圆上的点
GRADIENT_TRIANGLE gttri[360] = {};
for (int i = 0; i < 360; i++)
{
gttri[i].Vertex1 = 0;
gttri[i].Vertex2 = i + 1;
gttri[i].Vertex3 = (i + 1) % 360 + 1;
}
// 绘制圆形
GdiGradientFill(halphadc, vtri, 361, gttri, 360, GRADIENT_FILL_TRIANGLE);
// 将包含alpha通道的圆混合到目标缓冲绘图
// 然后删除相关设备和位图
BLENDFUNCTION bfalpha = { AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA };
GdiAlphaBlend(htargetdc, 0, 0, width, height, halphadc, 0, 0, width, height, bfalpha);
DeleteDC(halphadc);
DeleteObject(halphadc);
// 将目标缓冲绘图传送到设备
// 然后删除相关设备和位图
BitBlt(hdc, 0, 0, width, height, htargetdc, 0, 0, SRCCOPY);
DeleteDC(htargetdc);
DeleteObject(htargetbmp);
// 结束绘制
EndPaint(hWnd, &ps);
return 0;
}
[修改于 8年0个月前 - 2017/03/14 04:40:33]
GDI对32位alpha位图仅能进行COLORONCOLOR的缩放,也就是直接丢弃像素,不能实现HALFTONE缩放,也就没办法进行超采样除锯齿。
如果觉得GDI+比较慢,很难实现特殊效果的话,可以使用Direct2D/DirectWrite/WIC。
但是呢。。。Direct2D后来又走了错误的道路。。。
Direct2D 1.0倒是很好用,1.1就不行了,非得手工初始化D3D11然后绑上去,并且还要装Platform Update。。。
一个2D API搞得这么复杂让谁用。。。
加速图像处理常见的做法是BitBlt出来,进行运算,再BitBlt进去。如果CPU运算太慢,可以开SSE或AVX优化,或者直接调用D3D9做运算,面向高端的话也可以用C++AMP调用GPU。
引用 glcolor:感觉主要的性能瓶颈是内存位图合成而不是Blt,窗口绘制也就最后一步BitBlt。
可以试试这个开源库,也是国人写的:XXXXXXXXXXXXXXXXXX/skywind3000/BasicBitmap
中文blog页面:XXXXXXXXXXXXXyw……
200字以内,仅用于支线交流,主线讨论请采用回复功能。