Skip to content

Instantly share code, notes, and snippets.

@Shubhra22
Last active April 25, 2024 12:45
Show Gist options
  • Save Shubhra22/bab1052cd90b9f4b89b3 to your computer and use it in GitHub Desktop.
Save Shubhra22/bab1052cd90b9f4b89b3 to your computer and use it in GitHub Desktop.
Screen Capture of particular UI elements
using UnityEngine;
using System.Collections;
using System.IO;
using UnityEngine.UI;
public class ScreenshotNow : MonoBehaviour
{
public RectTransform rectT; // Assign the UI element which you wanna capture
public Image img;
int width; // width of the object to capture
int height; // height of the object to capture
// Use this for initialization
void Start ()
{
width = System.Convert.ToInt32(rectT.rect.width);
height = System.Convert.ToInt32(rectT.rect.height);
}
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButtonDown (0))
{
//StartCoroutine(takeScreenShot ()); // screenshot of a particular UI Element.
}
if (Input.GetKeyDown (KeyCode.A))
{
Application.CaptureScreenshot ("FullPageScreenShot.png");
}
}
public IEnumerator takeScreenShot()
{
yield return new WaitForEndOfFrame (); // it must be a coroutine
Vector2 temp = rectT.transform.position;
var startX = temp.x - width/2;
var startY = temp.y - height/2;
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
tex.ReadPixels (new Rect(startX, startY, width, height), 0, 0);
tex.Apply ();
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
Destroy(tex);
//File.WriteAllBytes(Application.dataPath + "ScreenShot.png", bytes);
string imgsrc = System.Convert.ToBase64String(bytes);
Texture2D scrnShot = new Texture2D(1, 1, TextureFormat.ARGB32, false);
scrnShot.LoadImage(System.Convert.FromBase64String(imgsrc));
Sprite sprite = Sprite.Create(scrnShot, new Rect(0, 0, scrnShot.width, scrnShot.height), new Vector2(.5f, .5f));
img.sprite = sprite;
}
public void Capture()
{
StartCoroutine(takeScreenShot()); // screenshot of a particular UI Element.
}
}
@AnshuNair
Copy link

AnshuNair commented Jan 27, 2022

I'd like to highlight one requirement for Straafe's solution to work exactly as they have posted it. The rectTransform you are using must not be rotated. i.e. it must have a rotation of (0.0.0).

If it is rotated, you must use a different corner for your startX and startY values. Also, depending on the rotation, you may need to swap your width and height parameters. For example, my rectTransform was rotated -90 on the Z, so it would fit better on a phone in portrait mode.

This is the logic that worked for me:

    Vector3[] corners = new Vector3[4];
    rectTransform.GetWorldCorners(corners);
    int startX = (int)corners[3].x;
    int startY = (int)corners[3].y;
    int width = (int)corners[0].y - (int)corners[3].y;
    int height = (int)corners[1].x - (int)corners[0].x;
    var tex = new Texture2D(height, width, TextureFormat.RGB24, false);
    tex.ReadPixels(new Rect(startX, startY, height, width), 0, 0);
    tex.Apply();

startX and startY must be taken from the corner that is closest to the bottom left corner of your screen. So, in my case, it was corners[3], not corners[0].
I was skeptical if this solution would work with screen space overlay but it does, so that's great. Thanks for the solution, Straafe!

@Straafe
Copy link

Straafe commented Jan 27, 2022

Hey, no problem, I'm glad it helped people, and nice improvement and note about rotation. We could even edit it further so it finds the appropriate corners to use automatically by comparing their world positions to see which is closest to the true bottom left (although I imagine in almost all cases it would be either the corners you used or I used).

@SaumyaSaurav-RedAppleTech

This script takes screenshot of just the required UI object and saves to disk.

`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](http://www.google.com/search?q=new+msdn.microsoft.com) WaitForEndOfFrame();

    //Get the corners of RectTransform rect and store it in a array vector
    Vector3[] corners = [new](http://www.google.com/search?q=new+msdn.microsoft.com) 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](http://www.google.com/search?q=new+msdn.microsoft.com) Texture2D(width, height, TextureFormat.RGB24, false);
    ss.ReadPixels([new](http://www.google.com/search?q=new+msdn.microsoft.com) 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);
}

}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment