using System; using System.IO; using UnityEditor; using UnityEngine; using UnityEngine.SceneManagement; namespace Streamingle.Editor.Utilities { public static class ResolutionScreenshotMenu { private const string MenuRoot = "Tools/Streamingle/Capture/Screenshots/Resolution/"; private const int MenuPriority = 500; private const string SaveFolderPrefsKey = "ScreenshotTool_SaveFolder"; private const string PrefixPrefsKey = "ScreenshotTool_Prefix"; [MenuItem(MenuRoot + "Custom...", false, MenuPriority)] private static void ShowCustomWindow() { ResolutionScreenshotWindow.ShowWindow(); } [MenuItem(MenuRoot + "Capture 1280x720 (HD)", false, MenuPriority + 10)] private static void Capture1280x720() { Capture(1280, 720); } [MenuItem(MenuRoot + "Capture 1920x1080 (FHD)", false, MenuPriority + 11)] private static void Capture1920x1080() { Capture(1920, 1080); } [MenuItem(MenuRoot + "Capture 2560x1440 (QHD)", false, MenuPriority + 12)] private static void Capture2560x1440() { Capture(2560, 1440); } [MenuItem(MenuRoot + "Capture 3840x2160 (4K)", false, MenuPriority + 13)] private static void Capture3840x2160() { Capture(3840, 2160); } [MenuItem(MenuRoot + "Capture 1080x1920 (Portrait)", false, MenuPriority + 20)] private static void Capture1080x1920() { Capture(1080, 1920); } [MenuItem(MenuRoot + "Capture 1080x1080 (Square)", false, MenuPriority + 21)] private static void Capture1080x1080() { Capture(1080, 1080); } [MenuItem(MenuRoot + "Open Screenshot Folder", false, MenuPriority + 100)] private static void OpenScreenshotFolder() { string folder = GetScreenshotFolder(); Directory.CreateDirectory(folder); EditorUtility.RevealInFinder(folder); } internal static void Capture(int width, int height, Camera camera = null, bool transparentBackground = false, bool revealAfterCapture = false) { if (width <= 0 || height <= 0) { EditorUtility.DisplayDialog("Screenshot", "Width and height must be greater than zero.", "OK"); return; } camera ??= FindDefaultCaptureCamera(); if (camera == null) { EditorUtility.DisplayDialog( "Screenshot", "No capture camera found. Select a Camera in the hierarchy or add a MainCamera-tagged camera.", "OK"); return; } string folder = GetScreenshotFolder(); Directory.CreateDirectory(folder); string filePath = BuildFilePath(folder, camera, width, height); try { RenderCameraToPng(camera, width, height, filePath, transparentBackground); Debug.Log($"[ResolutionScreenshot] Saved {width}x{height} screenshot: {filePath}"); if (IsPathUnderAssets(filePath)) { AssetDatabase.Refresh(); } if (revealAfterCapture) { EditorUtility.RevealInFinder(filePath); } } catch (Exception ex) { Debug.LogError($"[ResolutionScreenshot] Capture failed: {ex.Message}"); EditorUtility.DisplayDialog("Screenshot Failed", ex.Message, "OK"); } } internal static Camera FindDefaultCaptureCamera() { var selectedObject = Selection.activeGameObject; if (selectedObject != null) { var selectedCamera = selectedObject.GetComponent(); if (IsUsableSceneCamera(selectedCamera)) { return selectedCamera; } selectedCamera = selectedObject.GetComponentInChildren(true); if (IsUsableSceneCamera(selectedCamera)) { return selectedCamera; } } var mainCamera = Camera.main; if (IsUsableSceneCamera(mainCamera)) { return mainCamera; } Camera bestCamera = null; var cameras = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.None); foreach (var sceneCamera in cameras) { if (!IsUsableSceneCamera(sceneCamera)) { continue; } if (bestCamera == null || sceneCamera.depth > bestCamera.depth) { bestCamera = sceneCamera; } } if (bestCamera != null) { return bestCamera; } return SceneView.lastActiveSceneView != null ? SceneView.lastActiveSceneView.camera : null; } internal static string GetScreenshotFolder() { string defaultFolder = Path.GetFullPath(Path.Combine(Application.dataPath, "..", "Screenshots")); string savedFolder = EditorPrefs.GetString(SaveFolderPrefsKey, defaultFolder); return string.IsNullOrWhiteSpace(savedFolder) ? defaultFolder : Path.GetFullPath(savedFolder); } private static void RenderCameraToPng(Camera camera, int width, int height, string filePath, bool transparentBackground) { RenderTexture previousTargetTexture = camera.targetTexture; RenderTexture previousActiveTexture = RenderTexture.active; CameraClearFlags previousClearFlags = camera.clearFlags; Color previousBackgroundColor = camera.backgroundColor; RenderTexture renderTexture = null; Texture2D texture = null; try { int antiAliasing = Mathf.Max(1, QualitySettings.antiAliasing); renderTexture = RenderTexture.GetTemporary( width, height, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB, antiAliasing); camera.targetTexture = renderTexture; if (transparentBackground) { camera.clearFlags = CameraClearFlags.SolidColor; camera.backgroundColor = new Color(0f, 0f, 0f, 0f); } camera.Render(); TextureFormat textureFormat = transparentBackground ? TextureFormat.ARGB32 : TextureFormat.RGB24; texture = new Texture2D(width, height, textureFormat, false); RenderTexture.active = renderTexture; texture.ReadPixels(new Rect(0, 0, width, height), 0, 0); texture.Apply(); File.WriteAllBytes(filePath, texture.EncodeToPNG()); } finally { camera.targetTexture = previousTargetTexture; camera.clearFlags = previousClearFlags; camera.backgroundColor = previousBackgroundColor; RenderTexture.active = previousActiveTexture; if (texture != null) { UnityEngine.Object.DestroyImmediate(texture); } if (renderTexture != null) { RenderTexture.ReleaseTemporary(renderTexture); } } } private static bool IsUsableSceneCamera(Camera camera) { return camera != null && camera.isActiveAndEnabled && camera.gameObject.scene.IsValid() && !EditorUtility.IsPersistent(camera); } private static string BuildFilePath(string folder, Camera camera, int width, int height) { string prefix = SanitizeFilePart(EditorPrefs.GetString(PrefixPrefsKey, "Screenshot")); string sceneName = SanitizeFilePart(GetSceneName(camera)); string cameraName = SanitizeFilePart(camera.name); string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmssfff"); string fileName = $"{prefix}_{sceneName}_{cameraName}_{width}x{height}_{timestamp}.png"; return Path.Combine(folder, fileName); } private static string GetSceneName(Camera camera) { Scene scene = camera.gameObject.scene; if (scene.IsValid() && !string.IsNullOrWhiteSpace(scene.name)) { return scene.name; } Scene activeScene = SceneManager.GetActiveScene(); return !string.IsNullOrWhiteSpace(activeScene.name) ? activeScene.name : "UntitledScene"; } private static string SanitizeFilePart(string value) { if (string.IsNullOrWhiteSpace(value)) { return "Screenshot"; } foreach (char invalidChar in Path.GetInvalidFileNameChars()) { value = value.Replace(invalidChar, '_'); } return value.Trim(); } private static bool IsPathUnderAssets(string filePath) { string fullPath = Path.GetFullPath(filePath).Replace('\\', '/'); string assetsPath = Path.GetFullPath(Application.dataPath).Replace('\\', '/'); return fullPath.StartsWith(assetsPath + "/", StringComparison.OrdinalIgnoreCase); } } public sealed class ResolutionScreenshotWindow : EditorWindow { private Camera captureCamera; private int width = 1920; private int height = 1080; private bool transparentBackground; private bool revealAfterCapture = true; public static void ShowWindow() { var window = GetWindow("Resolution Screenshot"); window.minSize = new Vector2(360f, 230f); window.Show(); } private void OnEnable() { captureCamera = ResolutionScreenshotMenu.FindDefaultCaptureCamera(); } private void OnGUI() { EditorGUILayout.Space(8f); EditorGUILayout.LabelField("Resolution Screenshot", EditorStyles.boldLabel); EditorGUILayout.Space(4f); captureCamera = (Camera)EditorGUILayout.ObjectField("Camera", captureCamera, typeof(Camera), true); if (captureCamera == null) { EditorGUILayout.HelpBox("Uses selected Camera, Main Camera, then the first active scene Camera.", MessageType.Info); } EditorGUILayout.Space(6f); EditorGUILayout.BeginHorizontal(); width = Mathf.Max(1, EditorGUILayout.IntField("Width", width)); height = Mathf.Max(1, EditorGUILayout.IntField("Height", height)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(4f); EditorGUILayout.BeginHorizontal(); AddPresetButton("HD", 1280, 720); AddPresetButton("FHD", 1920, 1080); AddPresetButton("QHD", 2560, 1440); AddPresetButton("4K", 3840, 2160); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); AddPresetButton("Portrait", 1080, 1920); AddPresetButton("Square", 1080, 1080); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(6f); transparentBackground = EditorGUILayout.Toggle("Transparent Background", transparentBackground); revealAfterCapture = EditorGUILayout.Toggle("Reveal After Capture", revealAfterCapture); EditorGUILayout.Space(8f); EditorGUILayout.LabelField("Save Folder", ResolutionScreenshotMenu.GetScreenshotFolder(), EditorStyles.miniLabel); EditorGUILayout.Space(8f); if (GUILayout.Button("Capture", GUILayout.Height(32f))) { ResolutionScreenshotMenu.Capture(width, height, captureCamera, transparentBackground, revealAfterCapture); } } private void AddPresetButton(string label, int presetWidth, int presetHeight) { if (GUILayout.Button(label)) { width = presetWidth; height = presetHeight; } } } }