Taking screenshot of partial area

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))

2 Likes
 var width = 400;
 var height = 300;
 var startX = 200;
 var startY = 100;
 var tex = new Texture2D (width, height, TextureFormat.RGB24, false);

 tex.ReadPixels (Rect(startX, startY, width, height), 0, 0);
 tex.Apply ();

 // Encode texture into PNG
 var bytes = tex.EncodeToPNG();
 Destroy(tex);

 File.WriteAllBytes(Application.dataPath + "/../SavedScreen.png", bytes);
6 Likes

Wow. 7 years later and no accepted answer.

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);
4 Likes

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.

1 Like

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);
}
4 Likes

Hi,
this is giving me the following error from line 27:

Texture has out of range width / height
UnityEngine.Texture2D:.ctor (int,int,UnityEngine.TextureFormat,bool)

I checked the values and I got 59932.74 for the height and 89332.05 for the width. Which sounds ridiculously high …

Any idea why that happened?

thanks for the script.
I created my own modification:

    public RectTransform AreaToCapture;
    public string FileName; //filename needs the direction, name & extension, ex: \varios\myphoto.png

    public enum RectMode { RectStretched, RectCentered }
    public RectMode RectTransformMode;


    public void TakeScreenShoot()
    {
        StartCoroutine(coroutineTakeScreenShoot());
    }

    private IEnumerator coroutineTakeScreenShoot()
    {
        yield return new WaitForEndOfFrame();

        var width = 0;
        var height = 0;
        var startX = 0f;
        var startY = 0f;

        if (RectTransformMode == RectMode.RectStretched)
        {
            //these var are correct only for a panel setted to stretch
            width = (int)AreaToCapture.rect.width;
            height = (int)AreaToCapture.rect.height;
            startX = AreaToCapture.offsetMin.x;
            startY = AreaToCapture.offsetMin.y;

            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);
            File.WriteAllBytes(Application.dataPath + FileName, bytes);
        }

        if (RectTransformMode == RectMode.RectCentered)
        {
            /*Debug.Log("tamaño y: " + AreaToCapture.rect.height);
            Debug.Log("tamaño x: " + AreaToCapture.rect.width);
            Debug.Log("localposition x: " + AreaToCapture.transform.localPosition.x);
            Debug.Log("localposition y: " + AreaToCapture.transform.localPosition.y);
            Debug.Log("offsetMin y: " + AreaToCapture.offsetMin.y);
            Debug.Log("offsetMin y: " + -AreaToCapture.offsetMin.y);*/

            Vector2 min = AreaToCapture.anchorMin;
            min.x *= Screen.width;
            min.y *= Screen.height;

            min += AreaToCapture.offsetMin;

            Vector2 max = AreaToCapture.anchorMax;
            max.x *= Screen.width;
            max.y *= Screen.height;

            max += AreaToCapture.offsetMax;

            //Debug.Log(min + " " + max);

            //these var are correct only for a panel setted to stretch
            width = (int)AreaToCapture.rect.width;
            height = (int)AreaToCapture.rect.height;
            startX = min.x;
            startY = min.y;

            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);
            File.WriteAllBytes(Application.dataPath + FileName, bytes);
        }

        Debug.Log("Capture saved in: " + FileName);
    }

its necessary to select the rectTransform mode (stretched/center)

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);
    }
}
6 Likes

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));
    }
}