首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Bitblt截图

使用Bitblt截图
EN

Stack Overflow用户
提问于 2014-03-22 12:36:04
回答 2查看 1.7K关注 0票数 1

我正在寻找获取打印屏幕的最快方法,我发现使用Bitblt是我更好的选择,然而,它只适用于设备上下文句柄,这意味着对我来说,要从中检索位图,我必须使用包括CreateCompatibleBitmap在内的多个API,最终这可能与使用托管方式的时间相同,比如graphics.CopyFromScreen (对我来说有点慢,而且在2.3 the四核处理器上消耗了7-10%的CPU…)

然而,我仍然在寻找一种更干净的方法来从其中检索位图,所以我想出了这个代码:

代码语言:javascript
复制
<DllImport("user32.dll")> _
Public Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
End Function

<DllImport("user32.dll")> _
Public Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Integer
End Function

<DllImport("gdi32.dll")> _
Public Shared Function BitBlt(ByVal hdcDest As IntPtr, ByVal xDest As Integer, ByVal yDest As Integer, ByVal wDest As Integer, ByVal hDest As Integer, ByVal hdcSource As IntPtr, _
ByVal xSrc As Integer, ByVal ySrc As Integer, ByVal rop As TernaryRasterOperations) As Boolean
End Function

    Dim hwNd As IntPtr = Nothing

    hwNd = GetDC(GetDesktopWindow)

    picHandle = GetDC(Me.PictureBox1.Handle)

    BitBlt(picHandle, 0, 0, PictureBox1.Width, PictureBox1.Height, hwNd, 0, 0, TernaryRasterOperations.SRCCOPY)

    ReleaseDC(hwNd, picHandle)

用这个我可以达到30帧/秒。但正如我上面所说的,它有两个问题:

即使我在上面做的那样在picturebox上显示它完成了我想要的事情,它也不会调整到picturebox控件的大小,即使我将那些"0“值更改为picturebox的x和y坐标。我进一步搜索,发现有一个StretchBit应用程序接口,它确实会拉伸,但它也会降低质量,(即使使用参数“半色调”对SetStretchBltMode进行必要的调用,这样它也不会“破坏”像素),它也会降低性能,至少在10+ fps中是这样的。

但由于我需要将其作为位图对象,加上其他必要的应用程序接口,我最终获得了几乎一半的性能(15~ fps),这相当于graphics.CopyFromScreen。

所以,我在问,有没有其他方法可以在不损失性能的情况下使用Bitblt或类似的方法从屏幕上获取位图?

如果没有.Net的方式,我很乐意请求任何语言的方式来实现。

EN

回答 2

Stack Overflow用户

发布于 2014-03-22 13:00:45

如果你想要原始的性能,你必须远离托管代码。在Visual Studio中使用C++非常容易。您可以直接调用Windows API,从而绕过.NET运行时、应用程序的托管代码以及.NET中p/调用的开销。

如果您熟悉C#,您可以将您的C#代码转换为C++ (这应该很简单,需要做很多工作来取代C#)。

票数 0
EN

Stack Overflow用户

发布于 2014-03-23 02:27:48

代码语言:javascript
复制
Private Declare Function BitBlt Lib "GDI32" ( _
    ByVal hdcDest As Integer, _
    ByVal nXDest As Integer, _
    ByVal nYDest As Integer, _
    ByVal nWidth As Integer, _
    ByVal nHeight As Integer, _
    ByVal hdcSrc As Integer, _
    ByVal nXSrc As Integer, _
    ByVal nYSrc As Integer, _
    ByVal dwRop As System.Int32) As Boolean

Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef X As Long) As Short
Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef X As Long) As Short

Const SRCCOPY As Integer = &HCC0020

使用只有一个picturebox和一个标签的窗体。相应地设置picbox的锚点。在picbox down事件中:

代码语言:javascript
复制
Private Sub PictureBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    Dim Ctr1, Ctr2, Freq As Long
    Dim dbl As Double

    QueryPerformanceCounter(Ctr1)


    Dim desktopDC As IntPtr = Nothing
    Dim picboxDC As IntPtr = Nothing

    desktopDC = GetDC(New IntPtr(0))

    picboxDC = GetDC(PictureBox1.Handle)

    BitBlt(picboxDC, 0, 0, PictureBox1.Width, PictureBox1.Height, desktopDC, 0, 0, SRCCOPY)

    QueryPerformanceCounter(Ctr2)
    QueryPerformanceFrequency(Freq)

    dbl = (Ctr2 - Ctr1) / Freq

    dbl *= 1000000

    Label1.Text = dbl.ToString 'it is in microseconds

    ReleaseDC(New IntPtr(0), desktopDC)
    ReleaseDC(PictureBox1.Handle, picboxDC)

End Sub 

最大化表单并在picturebox中单击。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22573522

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档