使用Graphics.CopyFromScreen以150%缩放比例截取屏幕截图

时间:2015-09-07 12:25:21

标签: c# .net bitmap

我正在尝试创建屏幕的屏幕截图/位图。我写了这个函数:

public static Bitmap CreateScreenshot(Rectangle bounds)
{
    var bmpScreenshot = new Bitmap(bounds.Width, bounds.Height, 
                                   PixelFormat.Format32bppArgb);
    var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
    gfxScreenshot.CopyFromScreen(bounds.X, bounds.Y,
        0, 0,
        new Size(bounds.Size.Width, bounds.Size.Height),
        CopyPixelOperation.SourceCopy);
    return bmpScreenshot;
}

在我的叠加形式中调用此函数,该窗体应将位图绘制到自身上。我目前正在使用GDI +进行整个过程。

private void ScreenshotOverlay_Load(object sender, EventArgs e)
{
    foreach (Screen screen in Screen.AllScreens)
        Size += screen.Bounds.Size;
    Location = Screen.PrimaryScreen.Bounds.Location;

    _screenshot = BitmapHelper.CreateScreenshot(new Rectangle(new Point(0, 0), Size));
    Invalidate(); // The screenshot/bitmap is drawn here
}

是的,我稍后会处理位图,所以不用担心。 ;) 在我的笔记本电脑和台式电脑上,这很好用。我用不同的分辨率对此进行了测试,计算结果是正确的。我可以在表格上看到屏幕的图像。

问题始于Surface 3.所有元素的缩放比例均为1.5(150%)。这意味着DPI会发生变化。如果我尝试在那里截取屏幕截图,它只会捕获屏幕左上角但不是整个屏幕截图。 我已经通过Google和StackOverflow尝试了不同的方法:

  1. 获取DPI,将其除以96并将屏幕的大小分量(X和Y)乘以此因子。
  2. application.manifest 中添加一个条目,以使应用程序支持DPI。
  3. 第一种方式没有带来预期的结果。第二个做了,但整个应用程序必须进行调整,这在Windows窗体中非常复杂。

    现在我的问题是:有没有办法捕获整个屏幕的截图,即使它的scalation因子高于1(更高的DPI)? 必须有办法做到这一点,以使其在任何地方工作。

    但此时我没有真正的搜索结果可以帮助我。 提前谢谢。

2 个答案:

答案 0 :(得分:1)

试试这个,这是在SharpAVI的库中找到的。无论分辨率如何,它都适用于设备。我已经在Surface 3上以150%进行了测试。

System.Windows.Media.Matrix toDevice;
using (var source = new HwndSource(new HwndSourceParameters()))
{
    toDevice = source.CompositionTarget.TransformToDevice;
}
screenWidth = (int)Math.Round(SystemParameters.PrimaryScreenWidth * toDevice.M11);
screenHeight = (int)Math.Round(SystemParameters.PrimaryScreenHeight * toDevice.M22);

可在此处找到SharpAVI:https://github.com/baSSiLL/SharpAvi它适用于视频,但在获取每个帧时使用类似的copyFromScreen方法:

graphics.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(screenWidth, screenHeight));

答案 1 :(得分:0)

在截屏之前,您可以使DPI知道该过程:

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern bool SetProcessDPIAware();
    private static Bitmap Screenshot()
    {
        SetProcessDPIAware();
        var screen = System.Windows.Forms.Screen.PrimaryScreen;
        var rect = screen.Bounds;
        var size = rect.Size;

        Bitmap bmpScreenshot = new Bitmap(size.Width, size.Height);
        Graphics g = Graphics.FromImage(bmpScreenshot);
        g.CopyFromScreen(0, 0, 0, 0, size);

        return bmpScreenshot;
    }