在Windows Vista,Windows 7中截取屏幕截图,其中包含应用区域外的透明区域

时间:2010-06-07 00:34:34

标签: c# windows-7 gdi+ gdi windows-vista

我正在尝试截取应用程序的屏幕截图,并且我想使不属于应用程序区域的矩形部分变得透明。因此,例如在标准的Windows应用程序上,我想使圆角透明。

我写了一个快速测试应用程序,该应用程序适用于XP(或关闭aero的vista / windows 7):

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        Graphics g = e.Graphics;           

        // Just find a window to test with
        IntPtr hwnd = FindWindowByCaption(IntPtr.Zero, "Calculator");

        WINDOWINFO info = new WINDOWINFO();
        info.cbSize = (uint)Marshal.SizeOf(info);
        GetWindowInfo(hwnd, ref info);


        Rectangle r = Rectangle.FromLTRB(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
        IntPtr hrgn = CreateRectRgn(info.rcWindow.Left, info.rcWindow.Top, info.rcWindow.Right, info.rcWindow.Bottom);
        GetWindowRgn(hwnd, hrgn);

        // fill a rectangle which would be where I would probably 
        // write some mask color
        g.FillRectangle(Brushes.Red, r);

        // fill the region over the top, all I am trying to do here 
        // is show the contrast between the applications region and 
        // the rectangle that the region would be placed in
        Region region = Region.FromHrgn(hrgn);
        region.Translate(info.rcWindow.Left, info.rcWindow.Top);
        g.FillRegion(Brushes.Blue, region);
    }

当我在XP(或带有Aero的Vista / Windows 7)上运行此测试应用程序时,我得到类似这样的内容,这很棒,因为我可以使用这个可以在以后用于BitBlt的xor掩码。< / p>

删除了死的Imageshack链接 - 屏幕截图

问题是,在启用了Aero的Vista或Windows 7上,窗口上不一定有区域,实际上在大多数情况下没有。任何人都可以帮我找出在这些平台上构建这样的面具的方法吗?

以下是我已经尝试过的一些方法......

1。使用PrintWindow函数:这不起作用,因为它会在Aero关闭时返回窗口截图,此窗口与Aero返回的窗口形状不同

2使用Desktop Window Manager API获取完整尺寸的缩略图:这不起作用,因为它直接绘制到屏幕上,而且我可以告诉您无法获取屏幕截图直接从这个api。是的,我可以打开一个粉红色背景的窗口,显示缩略图,截取屏幕截图然后隐藏这个临时窗口,但这是一个糟糕的用户体验和完全黑客,我宁愿没有我的名字。

第3。使用Graphics.CopyFromScreen或其他一些pinvoke变体:这不起作用,因为我不能假设我需要信息的窗口位于屏幕上z顺序的顶部。 / p>

目前,我能想到的最佳解决方案是Windows 7和Vista上的特殊情况Aero通过对我绘制的一些图形路径进行硬编码来手动擦除角落但是这个解决方案会因为任何执行自定义皮肤的应用程序而变得很糟糕会打破这个。

你能想到另一个或更好的解决方案吗?

如果您在这里,感谢您花时间阅读本文,感谢您提供的任何帮助或指导!

4 个答案:

答案 0 :(得分:8)

如果您正在寻找已完成的应用程序,则7capture会捕获半透明效果,因此可以将图像保存为PNG格式以供以后合成。

编辑:

原始问题和注释表明您希望在Windows Vista / 7上生成一个区域,然后可以使用该区域屏蔽捕获图像的部分,就像使用Windows XP和非Aero UI一样。使用区域不会为您提供所需的结果,因为窗口轮廓不是作为区域计算的,而是作为具有可变透明度的图像 - RGBA。该图像中的Alpha通道是您的遮罩,但它不是像区域一样的开关遮罩,而是一个渐变遮罩,其中包含从像素完全包含到完全遮盖的一系列值。

虽然它使用了未记录的API,但http://spazzarama.wordpress.com/2009/02/12/screen-capture-with-vista-dwm/处的代码将捕获到RGBA缓冲区,然后您可以使用该缓冲区渲染或保存图像,阴影和其他半透明效果保持不变。

DwmCapture.cs更改

BackBufferFormat = Format.X8R8G8B8

BackBufferFormat = Format.A8R8G8B8

(x8的&GT; A8)

然后,您应该能够从捕获的缓冲区访问常用的RGB数据和透明度。然后可以将其保存为PNG或其他带有alpha通道的格式进行合成。

答案 1 :(得分:1)

删除了一个可怕的想法,但在90年代会很棒的

你说使用DWM API只允许你直接捕捉到屏幕......你能在屏幕外创建一个窗口(例如,X = -100000px,Y = -100000px)但是可见(甚至隐藏?)和画截图到它?因为当使用DWM时,每个窗口都有一个背景纹理,我认为即使目标不是直接在屏幕上,它仍然可以被绘制得很好。

此外,如果你想进入DirectX路线并访问支持窗口的实际DX纹理,我发现了一些可能有用的线索(特别是第一个链接):

答案 2 :(得分:0)

  
      
  1. 使用Graphics.CopyFromScreen或其他一些pinvoke变体:   这不起作用,因为我做不到   假设我需要的窗口   来自的信息是最重要的   屏幕上的z顺序。
  2.   

如果您知道需要哪个窗口信息,可以将它带到前面,调用Graphics.CopyFromScreen,然后重置其z-index?我从经验中知道,当物品在后台时,Aero会做出奇怪的事情,以使其玻璃界面正常工作(部分渲染等)。这可能不是很好的用户体验;但是,这将是一个特殊情况,仅在打开Aero时使用。

答案 3 :(得分:0)

您可以查看AeroShot的源代码,如主页上所述,它可以捕获圆边和Aero Glass透明效果,并将其保存为PNG文件。它是用C#编写的。