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