使用 ScreenCapture.CaptureScreenshot 捕获并保存屏幕截图

Capture and save screenshot with ScreenCapture.CaptureScreenshot

我一直在尝试截屏,然后立即用它来显示某种预览,有时有效,有时无效,我目前不在工作而且我不在这台计算机上没有统一,所以我会尝试即时重新创建它(这里和那里可能会有一些语法错误)

public GameObject screenshotPreview;

public void TakeScreenshot () {

        string imageName = "screenshot.png";

        // Take the screenshot
        ScreenCapture.CaptureScreenshot (imageName);

        // Read the data from the file
        byte[] data = File.ReadAllBytes(Application.persistentDataPath + "/" + imageName);

        // Create the texture
        Texture2D screenshotTexture = new Texture2D(Screen.width, Screen.height);

        // Load the image
        screenshotTexture.LoadImage(data);

        // Create a sprite
        Sprite screenshotSprite = Sprite.Create (screenshotTexture, new Rect(0, 0, Screen.width, Screen.height), new Vector2(0.5f, 0.5f) );

        // Set the sprite to the screenshotPreview
        screenshotPreview.GetComponent<Image> ().sprite = screenshotSprite;

}

据我所知,ScreenCapture.CaptureScreenshot 不是异步的,所以图像应该在我尝试加载数据之前就已经写入,但问题正如我之前所说的那样不起作用,它加载了一个带有红色问号的 8x8 纹理,这显然是纹理加载失败,但文件应该在那里,所以我不明白为什么它没有正确加载。

我尝试过的另一件事(这很恶心,但我对此感到厌倦并且运行没有想法)是放入更新方法等待一段时间然后执行用于加载数据并创建纹理、精灵并显示它的代码,但即便如此,它还是会失败几次,失败的频率比以前低,但它仍然失败,这让我相信即使创建了文件,它也没有完成 beign写了,有没有人知道这个的解决方法?任何建议表示赞赏。

作为额外信息,此项目正在 运行 iOS 设备中。

我在文档中没有看到任何说明它不是异步的内容。事实上,对于 Android(如果我没看错的话),它明确表示它是异步的。

就是说,我会在找不到文件时尝试拖延。将其放入协程中

FileInfo yourFile = new FileInfo("YourFile.png");
while (File.Exists(yourFile.name) || IsFileLocked(yourFile)) 
    yield return null;

IsFileLocked

您也可以尝试在其中进行一些调试检查,以查看文件出现(假设它曾经出现)需要多长时间(秒或帧)。

编辑:正如 derHugo 所指出的,文件存在并不意味着文件已经准备就绪。我已经编辑了代码来处理这个问题!但是它仍然没有涵盖文件已经存在的情况,在这种情况下你可能想要一个带有时间戳的动态文件名,或者你想先删除文件!

ScreenCapture.CaptureScreenshot 函数已知有很多问题。 是另外一个。

引用其 doc:

On Android this function returns immediately. The resulting screenshot is available later.

iOS 行为没有记录,但我们可以假设行为与 iOS 相同。截取屏幕截图后等待几帧,然后再尝试 read/load。

public IEnumerator TakeScreenshot()
{

    string imageName = "screenshot.png";

    // Take the screenshot
    ScreenCapture.CaptureScreenshot(imageName);

    //Wait for 4 frames
    for (int i = 0; i < 5; i++)
    {
        yield return null;
    }

    // Read the data from the file
    byte[] data = File.ReadAllBytes(Application.persistentDataPath + "/" + imageName);

    // Create the texture
    Texture2D screenshotTexture = new Texture2D(Screen.width, Screen.height);

    // Load the image
    screenshotTexture.LoadImage(data);

    // Create a sprite
    Sprite screenshotSprite = Sprite.Create(screenshotTexture, new Rect(0, 0, Screen.width, Screen.height), new Vector2(0.5f, 0.5f));

    // Set the sprite to the screenshotPreview
    screenshotPreview.GetComponent<Image>().sprite = screenshotSprite;

}

注意必须使用StartCoroutine(TakeScreenshot());调用此函数


如果这不起作用,请完全不要使用此功能。这是另一种在 Unity 中截取和保存屏幕截图的方法:

IEnumerator captureScreenshot()
{
    yield return new WaitForEndOfFrame();

    string path = Application.persistentDataPath + "Screenshots/"
            + "_" + screenshotCount + "_" + Screen.width + "X" + Screen.height + "" + ".png";

    Texture2D screenImage = new Texture2D(Screen.width, Screen.height);
    //Get Image from screen
    screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
    screenImage.Apply();
    //Convert to png
    byte[] imageBytes = screenImage.EncodeToPNG();

    //Save image to file
    System.IO.File.WriteAllBytes(path, imageBytes);
}

程序员的代码通过如下调用成功运行。它被设计为协程,因此不会干扰帧率。因此它应该被称为协程。确保 CallerObject 继承自 "MonoBehaviour".

 public class CallerObject : MonoBehaviour
{
    public void Caller()
    {
        String imagePath = Application.persistentDataPath + "/image.png";
        StartCoroutine(captureScreenshot(imagePath));
    }


    IEnumerator captureScreenshot(String imagePath)
    {
        yield return new WaitForEndOfFrame();
        //about to save an image capture
        Texture2D screenImage = new Texture2D(Screen.width, Screen.height);


        //Get Image from screen
        screenImage.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
        screenImage.Apply();

        Debug.Log(" screenImage.width" + screenImage.width + " texelSize" + screenImage.texelSize);
        //Convert to png
        byte[] imageBytes = screenImage.EncodeToPNG();

        Debug.Log("imagesBytes=" + imageBytes.Length);

        //Save image to file
        System.IO.File.WriteAllBytes(imagePath, imageBytes);
    }
}