6

我需要非常快速地打印 Windows 应用程序的打印屏幕才能从中制作视频……我一直在使用 C#,但我对任何可以使这个过程更快的语言持开放态度。

我使用了许多技术:

  • .net 函数:Bitmap.CopyFromScreen()
  • GDI
  • Direct3d/DirectX

我获得的最快速度是使用 GDI,但我仍然每秒获得不到 10 张照片。我需要更多一点,至少20或30...

这么简单的操作竟然要求这么高,我觉得很奇怪。看起来好像使用更快的 cpu 并没有改变这种情况。

我能做些什么?是否可以使用 gdi 或其他东西直接捕获应用程序的绘图?或者甚至是更低级别的函数来捕捉被扔到显卡上的信息?

对此问题的任何说明将不胜感激。非常感谢

4

2 回答 2

1

许多程序使用驱动程序并允许您的应用程序连接到较低级别的显示例程。我不完全确定这是如何完成的,但这是可能的。这是编写 Windows 驱动程序的起点。http://msdn.microsoft.com/en-us/library/ms809956.aspx

这是我刚刚通过谷歌找到的东西: http ://www.hmelyoff.com/index.php?section=17

于 2009-04-13T15:20:42.750 回答
1

您可能想使用类似Camtasia的东西。取决于你制作视频的原因。

我使用 Jeff 的User-Friendly Exception Handling的重写版本,他使用 GDI 的 BitBlt 来捕获屏幕截图。对我来说似乎足够快,但我没有对其进行基准测试,我们只是在抛出未处理的异常时将其用于一次拍摄。

#region Win32 API screenshot calls

// Win32 API calls necessary to support screen capture
[DllImport("gdi32", EntryPoint = "BitBlt", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int BitBlt(int hDestDC, int x, int y, int nWidth, int nHeight, int hSrcDC, int xSrc,
                                 int ySrc, int dwRop);

[DllImport("user32", EntryPoint = "GetDC", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int GetDC(int hwnd);

[DllImport("user32", EntryPoint = "ReleaseDC", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int ReleaseDC(int hwnd, int hdc);

#endregion

private static ImageFormat screenshotImageFormat = ImageFormat.Png;

/// <summary>
/// Takes a screenshot of the desktop and saves to filename and format specified
/// </summary>
/// <param name="fileName"></param>
private static void TakeScreenshotPrivate(string fileName)
{
    Rectangle r = Screen.PrimaryScreen.Bounds;

    using (Bitmap bitmap = new Bitmap(r.Right, r.Bottom))
    {
        const int SRCCOPY = 13369376;

        using (Graphics g = Graphics.FromImage(bitmap))
        {
            // Get a device context to the windows desktop and our destination  bitmaps
            int hdcSrc = GetDC(0);
            IntPtr hdcDest = g.GetHdc();

            // Copy what is on the desktop to the bitmap
            BitBlt(hdcDest.ToInt32(), 0, 0, r.Right, r.Bottom, hdcSrc, 0, 0, SRCCOPY);

            // Release device contexts
            g.ReleaseHdc(hdcDest);
            ReleaseDC(0, hdcSrc);

            string formatExtension = screenshotImageFormat.ToString().ToLower();
            string expectedExtension = string.Format(".{0}", formatExtension);

            if (Path.GetExtension(fileName) != expectedExtension)
            {
                fileName += expectedExtension;
            }

            switch (formatExtension)
            {
                case "jpeg":
                    BitmapToJPEG(bitmap, fileName, 80);
                    break;
                default:
                    bitmap.Save(fileName, screenshotImageFormat);
                    break;
            }

            // Save the complete path/filename of the screenshot for possible later use
            ScreenshotFullPath = fileName;
        }
    }
}

/// <summary>
/// Save bitmap object to JPEG of specified quality level
/// </summary>
/// <param name="bitmap"></param>
/// <param name="fileName"></param>
/// <param name="compression"></param>
private static void BitmapToJPEG(Image bitmap, string fileName, long compression)
{
    EncoderParameters encoderParameters = new EncoderParameters(1);
    ImageCodecInfo codecInfo = GetEncoderInfo("image/jpeg");

    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, compression);
    bitmap.Save(fileName, codecInfo, encoderParameters);
}
于 2009-04-13T15:30:49.137 回答