如何创建透明 Unity 窗口 + OS 的屏幕截图

Posted

技术标签:

【中文标题】如何创建透明 Unity 窗口 + OS 的屏幕截图【英文标题】:How to create a screenshot of a transparant Unity window + OS 【发布时间】:2020-03-09 10:50:34 【问题描述】:

因此,对于我们正在尝试创建的应用程序,我们希望将独立应用程序的 Unity 窗口透明化(除了几个按钮之外的所有内容)并让用户一起截取他们的视图/操作系统 + 统一层.

例如: 用户打开我们的应用程序,单击一个按钮,整个统一窗口(除了几个按钮)变成透明的。然后,用户可以像平常一样使用它的操作系统,而前面提到的按钮保持在顶部。然后,用户可以单击按钮来创建他们操作系统的屏幕截图,然后我们将把它保存到他们的系统中。例如,我们可以通过屏幕截图在用户操作系统之上显示 Unity(3D 模型、图像)中的任何内容。

目前,我们可以通过类似这样的设置将窗口变为透明:https://alastaira.wordpress.com/2015/06/15/creating-windowless-unity-applications/

效果很好,在窗口等中单击也是如此。但是,我们现在想创建一个屏幕截图并将其保存在某个地方。为此,我们尝试了多种方法,几年前,在我们将这个项目放在一边之前,我们通过一个自定义 dll 让它工作,该 dll 使用我们从内部调用的“使用 System.Drawing”代码。请参阅下面的此 dll 和代码示例。

using System.Drawing;

namespace ScreenShotDll

public class ScreenShotClass

    public static void TakeScreenShotRect(int srcX, int srcY, int dstX, int dstY) //both fullscreen screenshot and cropped rectangle screenshot
    

        int width = Math.Abs(srcX - dstX);
        int height = Math.Abs(srcY - dstY);

        Bitmap memoryImage;
        memoryImage = new Bitmap(width, height);
        Size s = new Size(memoryImage.Width, memoryImage.Height);

        Graphics memoryGraphics = Graphics.FromImage(memoryImage);

        memoryGraphics.CopyFromScreen(srcX, srcY, 0, 0, s);

        string str = "";

        try
        
            str = string.Format(AppDomain.CurrentDomain.BaseDirectory + @"Screenshot.png");
        
        catch (Exception er)
        
            Console.WriteLine("Sorry, there was an error: " + er.Message);
            Console.WriteLine();
        

        memoryImage.Save(str);
    

但是这似乎不再起作用了。我们在 Unity 的 IL2CPP 后端并收到错误:NotSupportedException: System.Drawing.Bitmap

我们也在尝试使用 Unity 中的 user32.dll 并使用它的 GetPixel、ReleaseDC 和 GetActiveWindow 函数,正如在几个论坛上发布的那样,但我们得到的只是一张白色图像。

任何调整我们的自定义 dll 的方法或任何其他方法都将受到高度赞赏。如果您需要更多信息,请告诉我。

【问题讨论】:

也许this 对你有帮助?也许您可以将其移植到运行时 @derHugo 我会看看。谢谢你。同时欢迎任何其他/新的建议。 @derHugo 不能移植它,因为它几乎完全依赖于 Unity 的编辑器功能。还有人有什么想法吗? 【参考方案1】:

几天后,我设法在 Unity 中解决了这个问题。

我使用以下代码制作窗口的屏幕截图,并将其保存为位图。然后将其保存在我的磁盘上以 .png 格式。

[DllImport("user32.dll", SetLastError = true)] static extern int GetSystemMetrics(int smIndex);
[DllImport("user32.dll", SetLastError = false)] static extern IntPtr GetDesktopWindow();
[DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC", SetLastError=true)] static extern IntPtr CreateCompatibleDC([In] IntPtr hdc);
[DllImport("gdi32.dll", EntryPoint = "DeleteDC")] public static extern bool DeleteDC([In] IntPtr hdc);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")] public static extern bool DeleteObject([In] IntPtr hObject);
[DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")] static extern IntPtr CreateCompatibleBitmap([In] IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll", EntryPoint = "SelectObject")] public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj);
[DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);

private void screenShot()

    Debug.Log("In screenShot!");
    int nScreenWidth = GetSystemMetrics(0);
    int nScreenHeight = GetSystemMetrics(1);
    IntPtr hDesktopWnd = GetDesktopWindow();
    IntPtr hDesktopDC = GetDC(hDesktopWnd);
    IntPtr hCaptureDC = CreateCompatibleDC(hDesktopDC);
    IntPtr hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, nScreenWidth, nScreenHeight);
    SelectObject(hCaptureDC, hCaptureBitmap);
    BitBlt(hCaptureDC, 0, 0, nScreenWidth, nScreenHeight, hDesktopDC, 0, 0, 0x00CC0020 | 0x40000000);

    Bitmap bmp = Image.FromHbitmap(hCaptureBitmap);

    ImageConverter converter = new ImageConverter();
    byte[] bytes = (byte[])converter.ConvertTo(bmp, typeof(byte[]));

    string path = Application.dataPath;
    if (Application.platform == RuntimePlatform.OSXPlayer) 
        path += "/../../";
    
    else if (Application.platform == RuntimePlatform.WindowsPlayer) 
        path += "/../";
    

    File.WriteAllBytes(path + "Screenshot" + ".png", bytes);

    ReleaseDC(hDesktopWnd, hDesktopDC);
    DeleteDC(hCaptureDC);
    DeleteObject(hCaptureBitmap);

【讨论】:

以上是关于如何创建透明 Unity 窗口 + OS 的屏幕截图的主要内容,如果未能解决你的问题,请参考以下文章

C#制作截图软件时,怎样不截取软件窗口本身? 看下图:软件自身也被截下来了

Selenium:如何使用 NUnit 创建测试证据报告

检测用户何时在 Unity 中截屏

如何使用 Eclipse 给 Android 模拟器截屏

如何使用unity3D制作游戏

如何将电子窗口附加到应用程序屏幕并动态调整大小