using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.UI;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Drawing;
|
|
|
|
using System.Text.RegularExpressions;
|
|
using System;
|
|
|
|
public class TextureSizeChecker : EditorWindow
|
|
{
|
|
private static TextureSizeChecker instance;
|
|
List<TextureInfo> _infoList = new List<TextureInfo>();
|
|
|
|
static Texture2D _targetPic;
|
|
static string _pathRoot;
|
|
static float _alpha_cut_off = 0f;
|
|
static int _horizontalSpace = 0;
|
|
static int _verticalSpace = 0;
|
|
static int _rate = 200;
|
|
static int _rateImage = 200;
|
|
static int _foreceHight = 23;
|
|
static string splitChar = "\t";
|
|
static string _ignore = "Tools,Fonts";
|
|
static string[] formatOption = new string[] { "CSV", "xls","txt" };
|
|
static int indexOfFormat;
|
|
static string[] sortOption = new string[] { "尺寸最大值", "文件体积"};
|
|
static int indexOfSort;
|
|
static bool _isSotrUp;
|
|
static SaveType _saveType = SaveType.csv;
|
|
static bool _ignore_effect = false;
|
|
static Encoding ENCODING = Encoding.GetEncoding("GB2312");
|
|
static string titleStr;
|
|
static bool _isCheckEmpty = true;
|
|
static string[] _ignore_list;
|
|
[MenuItem("Tools/检查图片")]
|
|
static void ShowExcelTools()
|
|
{
|
|
Init();
|
|
instance.Show();
|
|
}
|
|
|
|
enum SaveType
|
|
{
|
|
csv=0,
|
|
xls,
|
|
txt,
|
|
}
|
|
void OnGUI()
|
|
{
|
|
DrawOptions();
|
|
}
|
|
|
|
static bool Get2Flag(int num)
|
|
{
|
|
if (num < 1) return false;
|
|
return (num & num - 1) == 0;
|
|
}
|
|
|
|
private void DrawOptions()
|
|
{
|
|
|
|
_pathRoot = EditorGUILayout.TextField("指定目录", _pathRoot);
|
|
_ignore = EditorGUILayout.TextField("忽略目录关键字",_ignore);
|
|
EditorGUILayout.HelpBox("检查的时候会忽略有上面关键字的目录,用逗号‘,’分割", MessageType.Info);
|
|
_ignore_list = _ignore.Split(',');
|
|
|
|
if (GUILayout.Button("UI目录"))
|
|
{
|
|
_pathRoot = Application.dataPath + "/LuaFramework/AssetBundleRes/ui";
|
|
}
|
|
if (GUILayout.Button("资源目录"))
|
|
{
|
|
_pathRoot = Application.dataPath + "/LuaFramework/AssetBundleRes";
|
|
}
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.Space();
|
|
_isCheckEmpty = EditorGUILayout.Toggle("是否检查空白像素", _isCheckEmpty);
|
|
EditorGUILayout.HelpBox("检查图片中是否有多余的空白像素并且输出更多信息\n勾选检查将会变慢",MessageType.Info);
|
|
if (_isCheckEmpty)
|
|
{
|
|
_ignore_effect = true;
|
|
_ignore_effect = EditorGUILayout.Toggle("是否忽略特效图片", _ignore_effect);
|
|
EditorGUILayout.HelpBox("勾选将会在检查空白像素的时候忽略路径中带有 'effect' 的图片\n因为特效贴图有空白像素属于正常现象", MessageType.Info);
|
|
}
|
|
else
|
|
{
|
|
_ignore_effect = false;
|
|
}
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.Space();
|
|
indexOfFormat = EditorGUILayout.Popup("储存格式", indexOfFormat, formatOption);
|
|
_saveType = (SaveType)indexOfFormat;
|
|
|
|
if (_saveType == SaveType.csv)
|
|
{
|
|
splitChar = ",";
|
|
}
|
|
else if(_saveType == SaveType.xls)
|
|
{
|
|
splitChar = "\t";
|
|
}
|
|
else if(_saveType == SaveType.txt)
|
|
{
|
|
splitChar = "\r\n";
|
|
}
|
|
|
|
indexOfSort = EditorGUILayout.Popup("排序关键字", indexOfSort, sortOption);
|
|
_isSotrUp = EditorGUILayout.Toggle("升序", _isSotrUp);
|
|
if(_isSotrUp)
|
|
{
|
|
EditorGUILayout.HelpBox("升序排列", MessageType.Info);
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.HelpBox("降序排列", MessageType.Info);
|
|
}
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.Space();
|
|
|
|
titleStr = "尺寸最大值" + splitChar + "尺寸"+splitChar + "尺寸大小" + splitChar + "文件体积" + splitChar + "是否有空余像素" + splitChar + "非空范围X" + splitChar + "非空范围Y" + splitChar + "特效文件NPOT"+splitChar+"路径";
|
|
|
|
_rate = EditorGUILayout.IntField("查找文件速度(文件数/帧)", _rate);
|
|
_rateImage = EditorGUILayout.IntField("检查文件速度(文件数/帧)", _rateImage);
|
|
if (GUILayout.Button("转换"))
|
|
{
|
|
EditorCoroutineRunner.StartEditorCoroutine(Conver());
|
|
}
|
|
|
|
}
|
|
|
|
class TextureInfo
|
|
{
|
|
public Bitmap texture;
|
|
public string fileName;
|
|
public Vector2 size;
|
|
/// <summary>
|
|
/// 文件大小,体积
|
|
/// </summary>
|
|
public double volume;
|
|
/// <summary>
|
|
/// 图片尺寸,面积
|
|
/// </summary>
|
|
public int area;
|
|
/// <summary>
|
|
/// 是否有空余的像素
|
|
/// </summary>
|
|
public bool hasEmptyArea;
|
|
public int emptyAreaX_start;
|
|
public int emptyAreaX_end;
|
|
public int emptyAreaY_start;
|
|
public int emptyAreaY_end;
|
|
public bool isEffect;
|
|
public bool POT;
|
|
public int maxSize;
|
|
public TextureInfo(Bitmap pic, string clearPath)
|
|
{
|
|
texture = pic;
|
|
//fileName = clearPath.Replace("Assets", Application.dataPath);
|
|
fileName = clearPath;
|
|
size = new Vector2(pic.Width, pic.Height);
|
|
var fileInfo = new FileInfo(fileName);
|
|
volume = System.Math.Ceiling(fileInfo.Length / 1024.0);
|
|
area = pic.Width * pic.Height;
|
|
isEffect = clearPath.ToLower().Contains("effect");
|
|
POT = Get2Flag(pic.Width) && Get2Flag(pic.Height);
|
|
maxSize = Mathf.Max(pic.Height, pic.Width);
|
|
}
|
|
public string GetInfo()
|
|
{
|
|
string str = "";
|
|
str += maxSize + splitChar;
|
|
str += size.x + "x" + size.y + splitChar;
|
|
str += area + splitChar;
|
|
str += volume + " KB" + splitChar;
|
|
if(_isCheckEmpty)
|
|
{
|
|
str += hasEmptyArea + splitChar;
|
|
if (hasEmptyArea)
|
|
{
|
|
str += emptyAreaX_start + "~" + emptyAreaX_end + splitChar;
|
|
str += emptyAreaY_start + "~" + emptyAreaY_end + splitChar;
|
|
}
|
|
else
|
|
{
|
|
str += splitChar;
|
|
str += splitChar;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
str += splitChar;
|
|
str += splitChar;
|
|
str += splitChar;
|
|
}
|
|
if(isEffect)
|
|
{
|
|
str += POT + splitChar;
|
|
}
|
|
else
|
|
{
|
|
str += splitChar;
|
|
}
|
|
str += fileName + splitChar;
|
|
|
|
//str += "\n";
|
|
return str;
|
|
}
|
|
}
|
|
|
|
int CompareDinosBySize(TextureInfo t1, TextureInfo t2)
|
|
{
|
|
if (indexOfSort == 0)
|
|
{
|
|
if (t1.area == t2.area)
|
|
{
|
|
//面积相同比较文件体积
|
|
if(_isSotrUp)
|
|
{
|
|
return (int)(t1.volume - t2.volume);
|
|
}
|
|
else
|
|
{
|
|
return (int)(t2.volume - t1.volume);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//尺寸大的优先
|
|
float max1 = Mathf.Max(t1.size.x, t1.size.y);
|
|
float max2 = Mathf.Max(t2.size.x, t2.size.y);
|
|
if(_isSotrUp)
|
|
{
|
|
return (int)(max2 - max1);
|
|
}
|
|
else
|
|
{
|
|
return (int)(max1 - max2);
|
|
}
|
|
}
|
|
}
|
|
else if(indexOfSort == 1)
|
|
{
|
|
if(_isSotrUp)
|
|
{
|
|
return (int)(t2.volume - t1.volume);
|
|
}
|
|
else
|
|
{
|
|
return (int)(t1.volume - t2.volume);
|
|
}
|
|
}
|
|
return 1;
|
|
|
|
}
|
|
|
|
bool IsIgonrePath(string path)
|
|
{
|
|
foreach(var flag in _ignore_list)
|
|
{
|
|
if(path.ToLower().Contains(flag.ToLower()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
IEnumerator Conver()
|
|
{
|
|
_infoList.Clear();
|
|
var files = Directory.GetFiles(_pathRoot, "*.png*", SearchOption.AllDirectories);
|
|
List<string> texturePahts = new List<string>();
|
|
float count = 0;
|
|
foreach (var file in files)
|
|
{
|
|
|
|
count++;
|
|
if (count % _rate == 0)
|
|
{
|
|
yield return 1;
|
|
}
|
|
if (IsIgonrePath(file))
|
|
{
|
|
continue;
|
|
}
|
|
if (file.EndsWith(".png"))
|
|
{
|
|
var clearPaht = file.Replace(Application.dataPath, "Assets");
|
|
texturePahts.Add(clearPaht);
|
|
//Debug.Log(clearPaht);
|
|
|
|
EditorUtility.DisplayProgressBar("查找文件中的PNG···", file, count / files.Length);
|
|
|
|
}
|
|
}
|
|
var files2 = Directory.GetFiles(_pathRoot, "*.jpg*", SearchOption.AllDirectories);
|
|
count = 0;
|
|
foreach (var file in files2)
|
|
{
|
|
|
|
count++;
|
|
if (count % _rate == 0)
|
|
{
|
|
yield return 1;
|
|
}
|
|
if (IsIgonrePath(file))
|
|
{
|
|
continue;
|
|
}
|
|
if (file.EndsWith(".jpg"))
|
|
{
|
|
var clearPaht = file.Replace(Application.dataPath, "Assets");
|
|
texturePahts.Add(clearPaht);
|
|
//Debug.Log(clearPaht);
|
|
EditorUtility.DisplayProgressBar("查找文件中的JPG···",file, count / files2.Length);
|
|
|
|
}
|
|
}
|
|
var files3 = Directory.GetFiles(_pathRoot, "*.tga*", SearchOption.AllDirectories);
|
|
count = 0;
|
|
foreach (var file in files3)
|
|
{
|
|
count++;
|
|
if (count % _rate == 0)
|
|
{
|
|
yield return 1;
|
|
}
|
|
if (IsIgonrePath(file))
|
|
{
|
|
continue;
|
|
}
|
|
if (file.EndsWith(".tga"))
|
|
{
|
|
var clearPaht = file.Replace(Application.dataPath, "Assets");
|
|
texturePahts.Add(clearPaht);
|
|
//Debug.Log(clearPaht);
|
|
|
|
EditorUtility.DisplayProgressBar("查找文件中的TGA···", file, count / files3.Length);
|
|
|
|
}
|
|
}
|
|
|
|
List<string> error_list = new List<string>();
|
|
List<string> warning_list = new List<string>();
|
|
count = 0;
|
|
foreach (var singPath in texturePahts)
|
|
{
|
|
count++;
|
|
var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(singPath);
|
|
if (texture)
|
|
{
|
|
try
|
|
{
|
|
Bitmap pic;
|
|
if (singPath.Contains(".tga"))
|
|
{
|
|
ImageTGA tga = new ImageTGA(singPath);
|
|
if(tga.Copy_Error)
|
|
{
|
|
warning_list.Add(singPath);
|
|
}
|
|
pic = new Bitmap(tga.Image);
|
|
}
|
|
else
|
|
{
|
|
pic = Bitmap.FromFile(singPath) as Bitmap;
|
|
}
|
|
CheckSingleTexture(pic, singPath);
|
|
pic.Dispose();
|
|
}
|
|
catch (Exception exp)
|
|
{
|
|
error_list.Add(singPath);
|
|
Debug.LogError(singPath + "\n\n" + exp);
|
|
}
|
|
|
|
|
|
//var bs = t.EncodeToPNG();
|
|
//string lastName = singlePaht.Substring(singlePaht.LastIndexOf("\\"));
|
|
//Debug.Log(lastName);
|
|
//File.WriteAllBytes(newDir + lastName, bs);
|
|
}
|
|
if (count % _rateImage == 0)
|
|
{
|
|
yield return 1;
|
|
}
|
|
EditorUtility.DisplayProgressBar("检查图片中···(共"+texturePahts.Count+"个)"+count+"/"+texturePahts.Count, singPath, count / texturePahts.Count);
|
|
}
|
|
_infoList.Sort(CompareDinosBySize);
|
|
|
|
|
|
|
|
|
|
count = 0;
|
|
List<string> str = new List<string>();
|
|
str.Add(titleStr);
|
|
foreach (var info in _infoList)
|
|
{
|
|
count++;
|
|
str.Add(info.GetInfo());
|
|
if (count % _rateImage*30 == 0)
|
|
{
|
|
yield return 1;
|
|
}
|
|
EditorUtility.DisplayProgressBar("整理文件中···", info.fileName, count / _infoList.Count);
|
|
}
|
|
str.Add("以下文件出错");
|
|
str.AddRange(error_list);
|
|
str.Add("以下文件读取时候出现异常,可能出错");
|
|
str.AddRange(warning_list);
|
|
EditorUtility.DisplayProgressBar("写入文件中···", "", 0);
|
|
string newDir = Application.dataPath.Replace("Assets", "") + "/image_output";
|
|
if(_saveType == SaveType.csv)
|
|
{
|
|
newDir += ".csv";
|
|
}
|
|
else if(_saveType == SaveType.xls)
|
|
{
|
|
newDir += ".xls";
|
|
}
|
|
else if(_saveType == SaveType.txt)
|
|
{
|
|
newDir += ".txt";
|
|
}
|
|
if (_infoList.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
|
|
File.WriteAllLines(newDir, str.ToArray(), ENCODING);
|
|
}
|
|
catch(IOException exp)
|
|
{
|
|
EditorUtility.ClearProgressBar();
|
|
EditorUtility.DisplayDialog("提示", "错误,请先关闭写入目录的文件 ", "好的呢", "");
|
|
yield break;
|
|
}
|
|
}
|
|
EditorUtility.DisplayDialog("提示", "扫描完成", "GOOD", "");
|
|
EditorUtility.ClearProgressBar();
|
|
AssetDatabase.Refresh();
|
|
}
|
|
|
|
void CheckSingleTexture(Bitmap pic, string path)
|
|
{
|
|
TextureInfo info = new TextureInfo(pic, path);
|
|
_infoList.Add(info);
|
|
|
|
if (!_isCheckEmpty)
|
|
{
|
|
return;
|
|
}
|
|
if(_ignore_effect)
|
|
{
|
|
if(path.ToLower().Contains("effect"))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
Vector2 range_x = new Vector2(1, pic.Width);
|
|
Vector2 range_y = new Vector2(1, pic.Height);
|
|
bool hasEmpty = false;
|
|
//Debug.Log("图片尺寸 " + pic.Width + "," + pic.Width);
|
|
bool done = false;
|
|
//横轴扫描 从左到右
|
|
for (int i = 1; i < pic.Width; i++)
|
|
{
|
|
if (done)
|
|
{
|
|
break;
|
|
}
|
|
for (int j = 1; j < pic.Height; j++)
|
|
{
|
|
try
|
|
{
|
|
System.Drawing.Color col = pic.GetPixel(i, j);
|
|
// data[i, j] = col;
|
|
if (col.A > _alpha_cut_off)
|
|
{
|
|
range_x.x = i;
|
|
//Debug.LogFormat(" 从左到右点 {0},{1},{2}", i, j, col);
|
|
hasEmpty = true;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.LogErrorFormat("1: {0},{1}", i, j);
|
|
}
|
|
|
|
}
|
|
}
|
|
done = false;
|
|
//横轴扫描 从右到左
|
|
for (int i = pic.Width - 1; i > 0; i--)
|
|
{
|
|
if (done)
|
|
{
|
|
break;
|
|
}
|
|
for (int j = 1; j < pic.Height; j++)
|
|
{
|
|
try
|
|
{
|
|
System.Drawing.Color col = pic.GetPixel(i, j);
|
|
// data[i, j] = col;
|
|
if (col.A > _alpha_cut_off)
|
|
{
|
|
range_x.y = i + 1;
|
|
//Debug.LogFormat(" 从右到左点 {0},{1}", i, j);
|
|
hasEmpty = true;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.LogErrorFormat("2: {0},{1}", i, j);
|
|
}
|
|
}
|
|
}
|
|
done = false;
|
|
//纵轴扫描 从下到上
|
|
for (int i = 1; i < pic.Height; i++)
|
|
{
|
|
if (done)
|
|
{
|
|
break;
|
|
}
|
|
for (int j = 1; j < pic.Width; j++)
|
|
{
|
|
try
|
|
{
|
|
System.Drawing.Color col = pic.GetPixel(j, i);
|
|
// data[i, j] = col;
|
|
if (col.A > _alpha_cut_off)
|
|
{
|
|
range_y.x = i;
|
|
//Debug.LogFormat(" 从下到上点 {0},{1}", j, i);
|
|
hasEmpty = true;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.LogErrorFormat("3: {0},{1}", i, j);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
done = false;
|
|
//纵轴扫描 从上到下
|
|
for (int i = pic.Height - 1; i > 0; i--)
|
|
{
|
|
if (done)
|
|
{
|
|
break;
|
|
}
|
|
for (int j = 1; j < pic.Width; j++)
|
|
{
|
|
try
|
|
{
|
|
System.Drawing.Color col = pic.GetPixel(j, i);
|
|
// data[i, j] = col;
|
|
if (col.A > _alpha_cut_off)
|
|
{
|
|
range_y.y = i + 1;
|
|
//Debug.LogFormat(" 从上到下点 {0},{1}", j, i);
|
|
hasEmpty = true;
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.LogErrorFormat("4: {0},{1}", i, j);
|
|
}
|
|
|
|
}
|
|
}
|
|
if (range_x.x > range_x.y)
|
|
{
|
|
Debug.LogError("查找错误 ");
|
|
return;
|
|
}
|
|
if (range_y.x > range_y.y)
|
|
{
|
|
Debug.LogError("查找错误 ");
|
|
return;
|
|
}
|
|
range_x.x = Mathf.Clamp(range_x.x, 1, pic.Width);
|
|
range_x.y = Mathf.Clamp(range_x.y, 1, pic.Width);
|
|
range_y.x = Mathf.Clamp(range_y.x, 1, pic.Height);
|
|
range_y.y = Mathf.Clamp(range_y.y, 1, pic.Height);
|
|
//Debug.Log(range_x);
|
|
//Debug.Log(range_y);
|
|
//Debug.LogFormat("最左边的像素:{0},最后边的像素:{1},最上像素:{2},最下的像素:{3}", range_x.x, range_x.y, range_y.x, range_y.y);
|
|
|
|
|
|
info.emptyAreaX_start = (int)range_x.x;
|
|
info.emptyAreaY_start = (int)range_y.x;
|
|
info.emptyAreaX_end = (int)range_x.y;
|
|
info.emptyAreaY_end = (int)range_y.y;
|
|
if(range_x.x > 1 || range_x.y < pic.Width)
|
|
{
|
|
info.hasEmptyArea = true;
|
|
}
|
|
else if(range_y.x > 1 || range_y.y < pic.Height)
|
|
{
|
|
info.hasEmptyArea = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void OnSelectionChange()
|
|
{
|
|
//object[] selection = (object[])Selection.objects;
|
|
//Debug.Log(selection .Length);
|
|
////判断是否有对象被选中
|
|
//if (selection.Length != 1)
|
|
// return;
|
|
////遍历每一个对象判断不是文件夹
|
|
//string objPath = AssetDatabase.GetAssetPath((Object)selection[0]);
|
|
//Debug.Log(objPath);
|
|
//if( Directory.Exists(objPath) )
|
|
//{
|
|
// _pathRoot = objPath;
|
|
// Repaint();
|
|
//}
|
|
//else
|
|
//{
|
|
|
|
//}
|
|
}
|
|
|
|
private static void Init()
|
|
{
|
|
_targetPic = null;
|
|
instance = EditorWindow.GetWindow<TextureSizeChecker>("选项");
|
|
_pathRoot = Application.dataPath + "/LuaFramework/AssetBundleRes";
|
|
instance.position = new Rect(new Vector2(604, 290), new Vector2(650, 400));
|
|
}
|
|
}
|