転載防止用
TedLab_CaptureScreenshotEditor.cs
using System;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace TedLab
{
public class CaptureScreenShotWindow : EditorWindow
{
private const float settingSizeWaitTime = 1f;
// iOS用の解像度リスト
static CaptureResolution[] resolutions_IOS =
{
new CaptureResolution(1242, 2208),
new CaptureResolution(1242, 2688),
new CaptureResolution(2048, 2732),
};
[MenuItem("TedLab Editor/スクリーンショットキャプチャ")]
static void OpenWindow()
{
GetWindow(true, "[TedLab]スクリーンショットキャプチャ");
}
[Serializable]
class CaptureResolution{
public CaptureResolution(int _width, int _height){
width = _width;
height = _height;
}
public int width = 1920;
public int height = 1080;
}
static readonly string KeyPrefix = "TedLab_CaptureScreenShot_";
static readonly string PathKey = KeyPrefix + "Path";
static readonly string ReverseKey = KeyPrefix + "Reverse";
static readonly string StopTimeKey = KeyPrefix + "StopTime";
static readonly string ResoCountKey = KeyPrefix + "ResoCount";
static readonly string ResoWidthBaseKey = KeyPrefix + "ResoW_";
static readonly string ResoHeightBaseKey = KeyPrefix + "ResoH_";
string m_path = "";
bool m_started = false;
bool m_reverse = false;
bool m_stopTime = true;
[SerializeField] List captureResolutions = null;
SerializedObject resolutionSerializedObj;
SerializedProperty resolutionProp;
EditorCoroutine m_coroutine = null;
int m_selectedIndexOld = -1;
GameViewSizeGroupType m_currentGroupType;
private void OnEnable()
{
captureResolutions = new List(32);
// 読み込み
m_path = EditorPrefs.GetString( PathKey, "" );
m_reverse = EditorPrefs.GetBool( ReverseKey, false );
m_stopTime = EditorPrefs.GetBool( StopTimeKey, true );
int reso_count = EditorPrefs.GetInt( ResoCountKey, 0 );
for( int i=0; i<reso_count; ++i ) { string indexText = i.ToString("D2"); int width = EditorPrefs.GetInt( ResoWidthBaseKey + indexText, 0 ); int height = EditorPrefs.GetInt( ResoHeightBaseKey + indexText, 0); if( width > 0 && height > 0 ){
captureResolutions.Add( new CaptureResolution(width, height));
}
}
resolutionSerializedObj = new SerializedObject(this);
resolutionProp= resolutionSerializedObj.FindProperty("captureResolutions");
}
private void OnDisable()
{
if( m_coroutine != null )
{
m_coroutine.Stop();
m_coroutine = null;
}
if( m_timeScaleOld >= 0f ){
Time.timeScale = m_timeScaleOld;
m_timeScaleOld = -1f;
}
// 保存
EditorPrefs.SetString( PathKey, m_path );
EditorPrefs.SetBool( ReverseKey, m_reverse );
EditorPrefs.SetBool( StopTimeKey, m_stopTime );
int reso_count = captureResolutions.Count;
EditorPrefs.SetInt( ResoCountKey, reso_count );
for( int i=0; i<reso_count; ++i )
{
var reso = captureResolutions[i];
string indexText = i.ToString("D2");
EditorPrefs.SetInt( ResoWidthBaseKey + indexText, reso.width );
EditorPrefs.SetInt( ResoHeightBaseKey + indexText, reso.height );
}
}
void OnGUI()
{
resolutionSerializedObj.Update();
if( m_started )
{
GUILayout.Label("スクリーンショットを撮影中...");
}
else
{
GUILayout.Label("設定:");
m_reverse = GUILayout.Toggle( m_reverse, "縦横反転" );
m_stopTime = GUILayout.Toggle( m_stopTime, "撮影時に止める(TimeScale)" );
GUILayout.Space(16f);
GUILayout.Label("解像度リスト:");
EditorGUILayout.PropertyField(resolutionProp, true);
resolutionSerializedObj.ApplyModifiedProperties();
if (GUILayout.Button("解像度をクリア")) {
captureResolutions.Clear();
}
if (GUILayout.Button("iOS解像度を追加")) {
AddResolutions( resolutions_IOS );
}
GUILayout.Space(16f);
GUILayout.Label("保存フォルダ:");
m_path = GUILayout.TextField(m_path);
if (GUILayout.Button("フォルダを開く"))
{
string filePath = m_path;
filePath = filePath.Replace( '/', Path.DirectorySeparatorChar );
EditorUtility.RevealInFinder(filePath);
}
if (GUILayout.Button("マニュアルを開く")) {
OpenManual();
}
if (GUILayout.Button("スクリーンショットを保存")) {
Capture();
}
}
}
void AddResolutions( CaptureResolution[] resolutions )
{
foreach( var reso in resolutions ){
captureResolutions.Add( reso );
}
}
void Capture()
{
if( m_started){
Debug.Log( "Already Started Capture..." );
return;
}
// 解像度指定がない場合はそのまま
if( captureResolutions.Count <= 0 )
{
string dateString = DateTime.Now.ToString("yyyyMMddHHmmss");
string filePath = string.Format( Path.Combine(m_path, "ScreenCapture_{0}.png"), dateString );
Debug.Log(string.Format("Saved a new screenshot as {0}", filePath));
ScreenCapture.CaptureScreenshot(filePath);
}
// 複数キャプチャ
else
{
m_coroutine = EditorCoroutine.Start( MultipleCaptureScreen() );
}
}
void OpenManual()
{
string url = "https://tedenglish.site/unity-ex-multi-screenshots/";
Application.OpenURL( url );
}
float m_timeScaleOld = -1f;
IEnumerator MultipleCaptureScreen()
{
m_started = true;
string TmpLabel = "TedLabScreenCaptureResoTemp";
m_timeScaleOld = Time.timeScale;
if( m_stopTime ){
Time.timeScale = 0f;
}
foreach( CaptureResolution reso in captureResolutions )
{
int width = m_reverse ? reso.height : reso.width;
int height = m_reverse ? reso.width : reso.height;
string dateString = DateTime.Now.ToString("yyyyMMddHHmmss");
string filePath = string.Format( Path.Combine(m_path, "ScreenCapture_{0}_{1}.png"), dateString, width.ToString() + "x" + height.ToString() );
Debug.Log( string.Format("Save a new screenshot as {0}", filePath) );
StartCustomSize( TmpLabel, width, height );
yield return settingSizeWaitTime;
// キャプチャ&待つ
ScreenCapture.CaptureScreenshot(string.Format(filePath));
while( !IsSaved( filePath ) ){
yield return 0.1f;
}
EndCustomSize( TmpLabel, width, height );
}
Debug.Log( "Saved All Captures!!" );
if( m_stopTime ){
Time.timeScale = m_timeScaleOld;
m_timeScaleOld = -1f;
}
m_started = false;
m_coroutine = null;
yield return 0f;
}
// UnityEditor.GameViewSizeTypeと合わせる
public enum GameViewSizeType
{
AspectRatio = 0,
FixedResolution = 1,
}
void StartCustomSize( string name, int width, int height )
{
var asm = typeof(UnityEditor.Editor).Assembly;
Type gameViewType = asm.GetType("UnityEditor.GameView");
Type gameViewSize = asm.GetType("UnityEditor.GameViewSize");
Type gameViewSizes = asm.GetType("UnityEditor.GameViewSizes");
Type gameViewSizeType = asm.GetType("UnityEditor.GameViewSizeType");
Type gameViewSizeGroup = asm.GetType("UnityEditor.GameViewSizeGroup");
EditorWindow gameView = EditorWindow.GetWindow(gameViewType, false, "Game", false);
PropertyInfo currentSizeGroupType = gameViewType.GetProperty("currentSizeGroupType", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
m_currentGroupType = (GameViewSizeGroupType)currentSizeGroupType.GetValue(gameView, null);
MethodInfo getGroup = gameViewSizes.GetMethod("GetGroup");
Type scriptableSingleton = typeof(ScriptableSingleton<>).MakeGenericType(gameViewSizes);
PropertyInfo scriptableSingletonInstance = scriptableSingleton.GetProperty("instance");
object gameViewSizesInstance = scriptableSingletonInstance.GetValue(null, null);
object group = getGroup.Invoke(gameViewSizesInstance, new object[] { m_currentGroupType });
Type[] paramTypes = new Type[] { gameViewSize };
MethodInfo addCustomSize = gameViewSizeGroup.GetMethod("AddCustomSize", BindingFlags.Public | BindingFlags.Instance, null, paramTypes, null);
ConstructorInfo constructor = gameViewSize.GetConstructor( new Type[] { gameViewSizeType, typeof(int), typeof(int), typeof(string) } );
// インデックスを保持しておく
PropertyInfo selectedSizeIndex = gameViewType.GetProperty("selectedSizeIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
m_selectedIndexOld = (int)selectedSizeIndex.GetValue( gameView, null );
// 追加
{
object newSize = constructor.Invoke(new object[] { (int)GameViewSizeType.FixedResolution, width, height, name });
addCustomSize.Invoke(group, new object[] { newSize });
}
// 追加したのをインデックス設定
int index = FindSameResolution( group, name, width, height );
if( index >= 0 ){
selectedSizeIndex.SetValue( gameView, index, null);
}
}
void EndCustomSize( string name, int width, int height )
{
var asm = typeof(UnityEditor.Editor).Assembly;
Type gameViewSize = asm.GetType("UnityEditor.GameViewSize");
Type gameViewSizes = asm.GetType("UnityEditor.GameViewSizes");
Type gameViewSizeType = asm.GetType("UnityEditor.GameViewSizeType");
Type gameViewSizeGroup = asm.GetType("UnityEditor.GameViewSizeGroup");
MethodInfo getGroup = gameViewSizes.GetMethod("GetGroup");
Type scriptableSingleton = typeof(ScriptableSingleton<>).MakeGenericType(gameViewSizes);
PropertyInfo scriptableSingletonInstance = scriptableSingleton.GetProperty("instance");
object gameViewSizesInstance = scriptableSingletonInstance.GetValue(null, null);
object group = getGroup.Invoke(gameViewSizesInstance, new object[] { m_currentGroupType });
Type[] paramTypes = new Type[] { typeof(int) };
MethodInfo removeCustomSize = gameViewSizeGroup.GetMethod("RemoveCustomSize", BindingFlags.Public | BindingFlags.Instance, null, paramTypes, null);
// 同名のインデックスを探す
int index = FindSameResolution( group, name, width, height );
if( index >= 0 ){
removeCustomSize.Invoke( group, new object[] { index } );
}
// 元に戻す
Type gameViewType = asm.GetType("UnityEditor.GameView");
PropertyInfo selectedSizeIndex = gameViewType.GetProperty("selectedSizeIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
EditorWindow gameView = EditorWindow.GetWindow(gameViewType, false, "Game", false);
selectedSizeIndex.SetValue( gameView, m_selectedIndexOld, null);
}
// 同名のインデックスを探す
int FindSameResolution( object group, string name, int width, int height )
{
int index = -1;
var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts");
var displayTexts = getDisplayTexts.Invoke(group, null) as string[];
string targetName = string.Format("{0} ({1}x{2})", name, width, height);
for(int i=0; i<displayTexts.Length; ++i)
{
string textTmp = displayTexts[i];
if( textTmp == targetName ){
index = i;
break;
}
}
return index;
}
// 保存されているか
bool IsSaved( string path )
{
bool isExist = File.Exists( path );
bool isLocked = false;
FileStream stream = null;
try{
stream = new FileStream( path, FileMode.Open, FileAccess.ReadWrite, FileShare.None );
}catch{
isLocked = true;
}finally{
if( stream != null ){
stream.Close();
}
}
return isExist && !isLocked;
}
// コルーチン用
public class EditorCoroutine
{
public static EditorCoroutine Start( IEnumerator _routine )
{
var coroutine = new EditorCoroutine(_routine);
coroutine.Start();
return coroutine;
}
readonly IEnumerator routine;
float _waitTimer = 0f;
double _prevTime = 0;
EditorCoroutine( IEnumerator _routine ){
routine = _routine;
}
void Start(){
EditorApplication.update += Update;
_prevTime = EditorApplication.timeSinceStartup;
}
public void Stop(){
EditorApplication.update -= Update;
}
void Update()
{
var time = EditorApplication.timeSinceStartup;
var deltaTime = (float)(time - _prevTime);
_prevTime = time;
if(_waitTimer > 0f){
_waitTimer -= deltaTime;
if(_waitTimer > 0f){
return;
}
}
if (routine.MoveNext()){
_waitTimer = routine.Current;
}else{
Stop();
}
}
}
}
} // namespace TedLab



コメント