Skip to content

Instantly share code, notes, and snippets.

@markeahogan
Created August 3, 2023 07:02
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markeahogan/69fc4d9722eadc20882c9aeda261fc56 to your computer and use it in GitHub Desktop.
Save markeahogan/69fc4d9722eadc20882c9aeda261fc56 to your computer and use it in GitHub Desktop.
Adds method to save the whole inspector to a screenshot
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
/// <summary>
/// Provides functionality for screenshotting full editor windows, and the inspector in particular
/// </summary>
public static class InspectorCapture
{
private const int _tabsHeight = 20;
private const int _footer = 4;
/// <summary>
/// Takes a screenshot of the entire inspector
/// </summary>
[MenuItem("Popup Asylum/Capture Inspector")]
public static async void CaptureInspector()
{
EditorWindow inspector = EditorWindow.GetWindow(typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow"));
await CaptureWindow(inspector);
}
/// <summary>
/// Captures the window and saves it as a png in the project folder
/// </summary>
/// <param name="window">window to screenshot</param>
/// <returns>Task completed when the process finishes</returns>
public static async Task CaptureWindow(EditorWindow window)
{
var bytes = (await ScreenshotAsync(window)).EncodeToPNG();
var filename = $"{window.GetType().Name}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.png";
File.WriteAllBytes(Application.dataPath + $"/../{filename}", bytes);
}
/// <summary>
/// Scrolls the window to the top then incrementally scrolls to the bottom taking screenshots till the whole thing is captured
/// </summary>
/// <param name="window">The window to screenshot</param>
/// <returns>A texture containing the editor window</returns>
static async Task<Texture2D> ScreenshotAsync(EditorWindow window)
{
List<Color> pixels = new List<Color>();
float originalScroll = SetScroll(window);
var baseHeight = window.position.height - (_tabsHeight + _footer);
for (int i = 0; i < 64; i++)
{
float desiredScroll = baseHeight * i;
float scroll = await ScrollTo(desiredScroll);
int offset = (int)(desiredScroll - scroll);
pixels.InsertRange(0, ReadWindowPixels(window, offset));
if (offset > 0)
break;
}
SetScroll(window, originalScroll);
int width = (int)window.position.width;
int height = pixels.Count / width;
Texture2D texture = new Texture2D(width, height, TextureFormat.RGB24, false);
texture.SetPixels(pixels.ToArray());
return texture;
// wraps scrolling and delayedCall in a Task as scrolling requires a frame to update
Task<float> ScrollTo(float scroll)
{
float result = SetScroll(window, scroll);
var tcs = new TaskCompletionSource<float>();
EditorApplication.delayCall += () => tcs.TrySetResult(result);
return tcs.Task;
}
}
/// <summary>
/// Captures a section of the window
/// </summary>
/// <param name="window">Window to capture</param>
/// <param name="offset">an optional vertical offset from the bottom</param>
/// <returns></returns>
private static Color[] ReadWindowPixels(EditorWindow window, int offset = 0)
{
int width = (int)window.position.width;
int height = (int)window.position.height - (_tabsHeight + _footer + offset);
return UnityEditorInternal.InternalEditorUtility.ReadScreenPixel(window.position.position + new Vector2(0, _tabsHeight + offset), width, height);
}
/// <summary>
/// Sets the editor window's scroll, returns the resulting scroll value
/// </summary>
/// <param name="inspector">The window to scroll</param>
/// <param name="scroll">the y value of the scroll</param>
/// <returns>the value passed in clamped to the min max scroll of the window</returns>
private static float SetScroll(EditorWindow inspector, float scroll = -1)
{
var scrollViewField = inspector.GetType().GetField("m_ScrollView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var scrollView = scrollViewField.GetValue(inspector) as ScrollView;
if (scroll >= 0) scrollView.scrollOffset = new Vector2(0, scroll);
return scrollView.scrollOffset.y;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment