My game lets you dress up your character. i’d like to save off that image (but not the rest of the 800x600 screen) to a file. According to the help, i can use Application.CaptureScreen() to capture the full screen but how does one capture just one part of it?
(Sorry if this is a common question. i searched first for “screenshot” but that produced tons of hits that weren’t relevant (it’s a popular key word))
Well CaptainKiyaku’s answer (with a little modification, below) still works.
var width = 400;
var height = 300;
var startX = 200;
var startY = 100;
var tex = new Texture2D(width, height, TextureFormat.RGB24, false);
Rect rex = new Rect(startX, startY, width, height);
tex.ReadPixels(rex, 0, 0);
tex.Apply();
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
Destroy(tex);
System.IO.File.WriteAllBytes(Application.dataPath + "SavedScreen.png", bytes);
To make sure the screen is captured correctly, you should wait to perform ReadPixels until after the frame is fully rendered. You can accomplish this by calling your script (or at least ReadPixels and everything after) in the OnPostRender message or by using WaitForEndOfFrame.
Here is my solution how you can take a shot of an 2D UI object. It works with any resolution and aspect ratio (Screen Space - Camera). But I belive there is a better way.
[SerializeField] private RectTransform targetRect;
private Camera _camera;
private void Start()
{
_camera = Camera.main;
}
public void TakeScreenshot(string fileName)
{
StartCoroutine(CutSpriteFromScreen(fileName));
}
private IEnumerator CutSpriteFromScreen(string fileName)
{
yield return new WaitForEndOfFrame();
var corners = new Vector3[4];
targetRect.GetWorldCorners(corners);
var bl = RectTransformUtility.WorldToScreenPoint(_camera, corners[0]);
var tl = RectTransformUtility.WorldToScreenPoint(_camera, corners[1]);
var tr = RectTransformUtility.WorldToScreenPoint(_camera, corners[2]);
var height = tl.y - bl.y;
var width = tr.x - bl.x;
Texture2D tex = new Texture2D((int)width, (int)height, TextureFormat.RGB24, false);
Rect rex = new Rect(bl.x,bl.y,width,height);
tex.ReadPixels(rex, 0, 0);
tex.Apply();
var bytes = tex.EncodeToPNG();
Destroy(tex);
File.WriteAllBytes(Application.dataPath + fileName, bytes);
}
How to use - Make a empty game object, drag and drop this script and assign the required items in inspector panel.
and you are ready to take a screenshot.
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class TakeScreenshotAndSave : MonoBehaviour
{
//Object To Screenshot
[SerializeField] private RectTransform _objToScreenshot;
//Assign the button to take screenshot on clicking
[SerializeField] private Button _takeScreenshotButton;
void Start()
{
_takeScreenshotButton.onClick.AddListener(OnClickTakeScreenshotAndSaveButton);
}
private void OnClickTakeScreenshotAndSaveButton()
{
StartCoroutine(TakeSnapShotAndSave());
}
//Using a Coroutine instead of normal method
public IEnumerator TakeSnapShotAndSave()
{
//Code will throw error at runtime if this is removed
yield return new WaitForEndOfFrame();
//Get the corners of RectTransform rect and store it in a array vector
Vector3[] corners = new Vector3[4];
_objToScreenshot.GetWorldCorners(corners);
//Remove 100 and you will get error
int width = ((int)corners[3].x - (int)corners[0].x) - 100;
int height = (int)corners[1].y - (int)corners[0].y;
var startX = corners[0].x;
var startY = corners[0].y;
//Make a temporary texture and read pixels from it
Texture2D ss = new Texture2D(width, height, TextureFormat.RGB24, false);
ss.ReadPixels(new Rect(startX, startY, width, height), 0, 0);
ss.Apply();
Debug.Log("Start X : " + startX + " Start Y : " + startY);
Debug.Log("Screen Width : " + Screen.width + " Screen Height : " + Screen.height);
Debug.Log("Texture Width : " + width + " Texture Height : " + height);
//Save the screenshot to disk
byte[] byteArray = ss.EncodeToPNG();
string savePath = Application.persistentDataPath + "/ScreenshotSave.png";
System.IO.File.WriteAllBytes(savePath, byteArray);
Debug.Log("Screenshot Path : " + savePath);
// Destroy texture to avoid memory leaks
Destroy(ss);
}
}
Thank you very much for this, helped me a lot. Just to mention, i removed the “-100” part because it was cutting a part of my picture. Other than that thank you <3.
using UnityEngine;
using System.IO;
public class ScreenShotTaker : MonoBehaviour
{
public Camera screenshotCamera; // Assign the screenshot camera in the inspector
public int screenshotWidth = 3840; // Set desired width
public int screenshotHeight = 2160; // Set desired height
public void TakeTransparentScreenshot()
{
// Step 1: Enable the screenshot camera and set its background color to transparent
Doodle_Manager.instance.pen.SetActive(false);
screenshotCamera.gameObject.SetActive(true);
screenshotCamera.clearFlags = CameraClearFlags.SolidColor;
screenshotCamera.backgroundColor = new Color(0, 0, 0, 0); // Transparent background
// Step 2: Create a high-resolution RenderTexture with transparency
RenderTexture rt = new RenderTexture(screenshotWidth, screenshotHeight, 24, RenderTextureFormat.ARGB32);
screenshotCamera.targetTexture = rt;
// Step 3: Render the screenshot camera view to the RenderTexture
RenderTexture.active = rt;
screenshotCamera.Render();
// Step 4: Create a high-resolution Texture2D with transparency to store the rendered image
Texture2D screenShot = new Texture2D(screenshotWidth, screenshotHeight, TextureFormat.RGBA32, false);
screenShot.ReadPixels(new Rect(0, 0, screenshotWidth, screenshotHeight), 0, 0);
screenShot.Apply();
// Step 5: Save the Texture2D as a PNG file with transparency
byte[] bytes = screenShot.EncodeToPNG();
string filename = Path.Combine(Application.persistentDataPath, "TransparentScreenshot.png");
File.WriteAllBytes(filename, bytes);
// Clean up
screenshotCamera.targetTexture = null;
RenderTexture.active = null;
Destroy(rt);
// Step 6: Disable the screenshot camera
screenshotCamera.gameObject.SetActive(false);
Doodle_Manager.instance.pen.SetActive(true);
Debug.Log("Transparent screenshot saved to: " + filename);
}
// Step 7: Convert the Texture2D to Sprite
public Sprite TextureToSprite(Texture2D texture)
{
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
}
}