-
-
Save Shubhra22/bab1052cd90b9f4b89b3 to your computer and use it in GitHub Desktop.
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. | |
} | |
} |
Hi Strrafe i am using above code for screen shot the particular area. But the error is coming is "trying to read pixels out of bounds" . I am using your above code Vector3 line code. But it is not working.
@Straafe You are amazing! This solved the scaling issue!
Thanks for this! You are amazing!
Jesus THANK YOU SO MUCH FOR THIS! I have been trying to find a solution for AGES!
Hi, I looked around for a few days on this. Pieced this together for this to work. I kept getting an error with the previous code. Also make sure your rect window is not larger than the actual screen size. You'll get a render texture error.
Rect rect = RectTransformUtility.PixelAdjustRect(rectT, canvas); //public vars
int textWidth = System.Convert.ToInt32(rect.width); // width of the object to capture
int textHeight = System.Convert.ToInt32(rect.height); // height of the object to capture
var startX = System.Convert.ToInt32(rect.x) + Screen.width / 2; // offset X
var startY = System.Convert.ToInt32(rect.y) + Screen.height / 2; // offset Y
RenderTexture rt = new RenderTexture(Screen.width , Screen.height , 24);
Camera.main.targetTexture = rt;
Texture2D screenShot = new Texture2D(textWidth , textHeight , textForm, false);
Camera.main.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(startX, startY, textWidth, textHeight), 0, 0);
Camera.main.targetTexture = null;
RenderTexture.active = null;
Destroy(rt);
byte[] bytes = screenShot.EncodeToPNG();
string filename = ScreenshotName("iOS+", (textWidth ).ToString(), (textHeight).ToString());
if (!Directory.Exists(Application.persistentDataPath + "/screenshots/"))
Directory.CreateDirectory(Application.persistentDataPath + "/screenshots/");
System.IO.File.WriteAllBytes(filename, bytes);
@gangstageek you don't need to render the camera to a RenderTexture, doing ".ReadPixels" will read directly from the current pixels of the screen at the end of a render frame automatically. That is if you want to grab what is on screen at the moment.
The only reason to use the RenderTexture method is if you are using an alternate camera to grab the UI from that is not currently in view.
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!
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).
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);
}
}`
I'm getting these errors when trying to use this script:
[d3d11] attempting to ReadPixels outside of RenderTexture bounds!
and
Thread is not attached to scripting runtime
or
Trying to read pixels out of bounds
EDIT:
I think Unity has changed since this example was made. The dimensions were about 50% too large. I got it to work in Unity 2018 again, but changed the startX/startY and width/height to below: