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位色,即在提交颜色之前要进行预乘:
<code class="language-cpp">red = red * alpha / 0xff; green = green * alpha / 0xff; blue = blue * alpha / 0xff; </code>
GdiGradientFill比较特殊,颜色范围为0x0000到0xff00:
<code class="language-cpp">red = red * alpha / 0xff00; green = green * alpha / 0xff00; blue = blue * alpha / 0xff00; </code>
这几个函数比较慢,为了提高效率,建议只在内存位图中进行GdiGradientFill和GdiAlphaBlend,最后一次BitBlt到设备。
Windows NT还支持以下两个函数:
MaskBlt:带掩码的传送
PlgBlt:平行四边形传送,可以旋转和挤压,允许有掩码,但有掩码的情况下不能旋转和挤压。
如果以上函数全部使用,则程序只能支持Windows 2000以上操作系统。
所有操作系统都支持的传送:
BitBlt:按位传送
StretchBlt:带伸缩的传送
PatBlt:画刷传送
GdiGradientFill和GdiAlphaBlend示例代码:
<code class="language-cpp"> 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; } </code>
[修改于 7年9个月前 - 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……
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |
200字以内,仅用于支线交流,主线讨论请采用回复功能。