unity 导入图片后,可选择精灵表自动切片,并可以导出为png

脚本源代码:

cs 复制代码
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System.IO;
using UnityEditorInternal;
using System.Collections.Generic;
using System;


public class TextureImporterWindow : EditorWindow
{
    private string folderPath = "D:/";
    private string filePath = "D:/";
    private string searchPattern = "*.png";
    private string savePath = "C:/Users/26679/Desktop";

    [MenuItem("Tools/导入图片")]
    public static void ShowWindow()
    {
        GetWindow<TextureImporterWindow>("导入图片窗口");
    }

    [Obsolete]
    void OnGUI()
    {
        // 顶部留白10像素
        GUILayout.Space(10);
        EditorGUILayout.BeginVertical("box");
        GUILayout.Label("文件夹导入", EditorStyles.boldLabel);
        // 路径设置
        folderPath = EditorGUILayout.TextField("文件夹路径:", folderPath);
        // 文件过滤
        searchPattern = EditorGUILayout.TextField("筛选文件格式:", searchPattern);
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("浏览", GUILayout.Width(80)))
        {
            folderPath = EditorUtility.OpenFolderPanel("选择一个文件夹", "D:/", "");
        }
        // 导入按钮
        if (GUILayout.Button("全部导入"))
        {
            if (Directory.Exists(folderPath))
            {
                ImportTexturesFromFolder(folderPath, searchPattern);
            }
            else
            {
                EditorUtility.DisplayDialog("Error", "文件夹不存在!", "OK");
            }
        }
        EditorGUILayout.EndHorizontal();
        GUILayout.EndVertical();

        GUILayout.Space(20);
        EditorGUILayout.BeginVertical("box");
        GUILayout.Label("单个图片导入", EditorStyles.boldLabel);
        EditorGUILayout.BeginHorizontal("box");
        filePath = EditorGUILayout.TextField("图片路径:", filePath);
        if (GUILayout.Button("浏览", GUILayout.Width(80)))
        {
            // 打开文件选择对话框
            filePath = EditorUtility.OpenFilePanel("请选择图片文件", "", "png,jpg,jpeg");
        }
        // 导入按钮
        if (GUILayout.Button("导入"))
        {
            if (!string.IsNullOrEmpty(filePath))
            {
                ImportTexturesFromFile(filePath);
            }
            else
            {
                EditorUtility.DisplayDialog("Error", "文件不存在!", "OK");
            }
        }
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.EndVertical();

        GUILayout.Space(20);
        EditorGUILayout.BeginVertical("box");
        GUILayout.Label("将选中的Texture资源全部切片(用于将精灵表每一帧切割成片)", EditorStyles.boldLabel);
        // 切割按钮
        if (GUILayout.Button("切片为Sprites"))
        {
            // 获取所有选中的纹理资源
            Texture2D[] textures = Selection.GetFiltered<Texture2D>(SelectionMode.Assets);

            if (textures.Length > 0)
            {
                foreach (Texture2D texture in textures)
                {
                    string path = AssetDatabase.GetAssetPath(texture);
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;

                    if (importer != null)
                    {
                        importer.textureType = TextureImporterType.Sprite;//纹理类型为Sprite
                        // importer.spriteImportMode = SpriteImportMode.Single;//Sprite模式为多个;
                        importer.filterMode = FilterMode.Point;//过滤模式为点; 对像素图处理比较好,还有其它双线算法;
                        importer.textureCompression = TextureImporterCompression.Uncompressed;//不压缩;
                        importer.isReadable = true;//可读写;
                        importer.maxTextureSize = 2048;
                        importer.SaveAndReimport();
                    }
                    else
                    {
                        Debug.Log("导入设置失败!");
                    }
                    DoAutomaticSlicing(false, texture);
                }
            }
            else
            {
                Debug.LogWarning("0 个Texture2D 资源被选中!");
            }
        }
        EditorGUILayout.BeginHorizontal("box");
        savePath = EditorGUILayout.TextField("保存路径:", savePath);
        if (GUILayout.Button("浏览", GUILayout.Width(80)))
        {
            // 打开文件选择对话框
            savePath = EditorUtility.OpenFolderPanel("选择一个文件夹", "D:/", "");
        }
        // 切割按钮
        if (GUILayout.Button("切片导出png"))
        {
            // 获取所有选中的纹理资源
            Texture2D[] textures = Selection.GetFiltered<Texture2D>(SelectionMode.Assets);

            if (textures.Length > 0)
            {
                foreach (Texture2D texture in textures)
                {
                    string path = AssetDatabase.GetAssetPath(texture);
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;

                    if (importer != null)
                    {
                        importer.textureType = TextureImporterType.Sprite;//纹理类型为Sprite
                        importer.spriteImportMode = SpriteImportMode.Multiple;//Sprite模式为多个;
                        importer.filterMode = FilterMode.Point;//过滤模式为点; 对像素图处理比较好,还有其它双线算法;
                        importer.textureCompression = TextureImporterCompression.Uncompressed;//不压缩;
                        importer.isReadable = true;//可读写;
                        importer.maxTextureSize = 2048;
                        importer.SaveAndReimport();
                    }
                    else
                    {
                        Debug.Log("导入设置失败!");
                    }
                    DoAutomaticSlicing(true, texture);
                }
            }
            else
            {
                Debug.LogWarning("0 个Texture2D 资源被选中!");
            }
        }

        EditorGUILayout.EndHorizontal();
        EditorGUILayout.EndVertical();


        GUILayout.Space(20);
        if (GUILayout.Button("test"))
        {
            Debug.Log("This is a test!");

            //测试代码;
        }

    }

    #region 图片导入
    void ImportTexturesFromFolder(string path, string pattern)
    {
        string[] files = Directory.GetFiles(path, pattern, SearchOption.AllDirectories);
        string projectPath = Application.dataPath;
        string targetFolder = "Assets/ImportedTextures/" + new DirectoryInfo(folderPath).Name + "/";

        // 创建目标文件夹
        if (!AssetDatabase.IsValidFolder(targetFolder))
        {
            AssetDatabase.CreateFolder("Assets", "ImportedTextures");
            AssetDatabase.CreateFolder("Assets/ImportedTextures", new DirectoryInfo(folderPath).Name);
        }

        int successCount = 0;
        foreach (string file in files)
        {
            try
            {
                string fileName = Path.GetFileName(file);
                string destPath = Path.Combine(targetFolder, fileName);

                // 复制文件到项目目录
                File.Copy(file, destPath, true);
                // Debug.Log($"复制: {file} -> {destPath}");

                successCount++;
            }
            catch (System.Exception e)
            {
                Debug.LogError($"导入失败 {file}: {e.Message}");
            }
        }

        // 刷新资源数据库
        AssetDatabase.Refresh();

        // 设置导入设置
        foreach (string file in files)
        {
            string fileName = Path.GetFileName(file);
            string assetPath = $"{targetFolder}{fileName}";

            TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
            if (importer != null)
            {
                importer.textureType = TextureImporterType.Sprite;//纹理类型为Sprite
                importer.spriteImportMode = SpriteImportMode.Multiple;//Sprite模式为单个;
                importer.filterMode = FilterMode.Point;//过滤模式为点; 对像素图处理比较好,还有其它双线算法;
                importer.textureCompression = TextureImporterCompression.Uncompressed;//不压缩;
                importer.isReadable = true;//可读写;
                importer.maxTextureSize = 2048;
                importer.SaveAndReimport();
            }
            else
            {
                Debug.Log("importer 为null");
            }
        }

        EditorUtility.DisplayDialog("导入完成",
            $"导入成功 {successCount}/{files.Length} textures", "OK");
    }
    void ImportTexturesFromFile(string file)
    {
        string projectPath = Application.dataPath;
        string targetFolder = "Assets/ImportedTextures/";

        // 创建目标文件夹
        if (!AssetDatabase.IsValidFolder(targetFolder))
        {
            AssetDatabase.CreateFolder("Assets", "ImportedTextures");
        }
        try
        {
            string fileName = Path.GetFileName(file);
            string destPath = Path.Combine(targetFolder, fileName);

            // 复制文件到项目目录
            File.Copy(file, destPath, true);
            // Debug.Log($"Copied: {file} -> {destPath}");

            // 刷新资源数据库
            AssetDatabase.Refresh();

            // 设置导入设置
            string assetPath = $"Assets/ImportedTextures/{fileName}";

            TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
            if (importer != null)
            {
                importer.textureType = TextureImporterType.Sprite;//纹理类型为Sprite
                importer.spriteImportMode = SpriteImportMode.Multiple;//Sprite模式为单个;
                importer.filterMode = FilterMode.Point;//过滤模式为点; 对像素图处理比较好,还有其它双线算法;
                importer.textureCompression = TextureImporterCompression.Uncompressed;//不压缩;
                importer.isReadable = true;//可读写;
                importer.maxTextureSize = 2048;
                importer.SaveAndReimport();
            }

            EditorUtility.DisplayDialog("导入完成!",
                $"成功导入 1 textures", "OK");

        }
        catch (System.Exception e)
        {
            Debug.LogError($"Failed to import {file}: {e.Message}");
        }
    }
    #endregion

    #region  Slice图片
    [Obsolete]
    private void DoAutomaticSlicing(bool isExport, Texture2D OrigonTxr, int minimumSpriteSize = 4)
    {
        Texture2D copyTexture = new Texture2D(OrigonTxr.width, OrigonTxr.height);
        copyTexture.SetPixels(OrigonTxr.GetPixels());
        copyTexture.Apply();
        Rect[] one = InternalSpriteUtility.GenerateAutomaticSpriteRectangles(copyTexture, minimumSpriteSize, 0);
        List<Rect> frames = new List<Rect>(one);
        frames = SortRects(frames, OrigonTxr.width);
        int index = 0;
        if (isExport)
        {
            foreach (Rect frame in frames)
            {
                ExportSpriteRectToPNG(OrigonTxr, frame, index++);

            }
            Debug.Log($"源{OrigonTxr.name}已经成功导出{index}张png图片,并保存到:{savePath}");

        }
        else
        {
            string path = AssetDatabase.GetAssetPath(OrigonTxr);
            TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
            if (importer != null)
            {
                importer.textureType = TextureImporterType.Sprite;//纹理类型为Sprite
                importer.spriteImportMode = SpriteImportMode.Multiple;//Sprite模式为多个;
                importer.filterMode = FilterMode.Point;//过滤模式为点; 对像素图处理比较好,还有其它双线算法;
                importer.textureCompression = TextureImporterCompression.Uncompressed;//不压缩;
                importer.isReadable = true;//可读写;
                importer.maxTextureSize = 2048;
                importer.SaveAndReimport();
            }
            else
            {
                Debug.Log("importer 为null");
            }
            List<SpriteMetaData> metas = new List<SpriteMetaData>();//于生成精灵的编辑器数据。表的名字;用于给子图命名;
            foreach (Rect rect in frames)//生成精灵小图;
            {
                SpriteMetaData meta = new SpriteMetaData();
                meta.rect = rect;
                meta.name = OrigonTxr.name + "_" + index++;
                metas.Add(meta);
            }

            importer.spritesheet = metas.ToArray();//精灵小图数组添加到父精灵图后;
            Debug.Log($"{OrigonTxr.name}成功生成{metas.Count} 个子Sprites ! ");
        }
    }
    // 1. Find top-most rectangle
    // 2. Sweep it vertically to find out all rects from that "row"
    // 3. goto 1.
    // This will give us nicely sorted left->right top->down list of rectangles
    // Works for most sprite sheets pretty nicely
    private List<Rect> SortRects(List<Rect> rects, int width)
    {
        List<Rect> result = new List<Rect>();

        while (rects.Count > 0)
        {
            // Because the slicing algorithm works from bottom-up, the topmost rect is the last one in the array
            Rect r = rects[rects.Count - 1];
            Rect sweepRect = new Rect(0, r.yMin, width, r.height);

            List<Rect> rowRects = RectSweep(rects, sweepRect);

            if (rowRects.Count > 0)
                result.AddRange(rowRects);
            else
            {
                // We didn't find any rects, just dump the remaining rects and continue
                result.AddRange(rects);
                break;
            }
        }
        return result;
    }
    private List<Rect> RectSweep(List<Rect> rects, Rect sweepRect)
    {
        if (rects == null || rects.Count == 0)
            return new List<Rect>();

        List<Rect> containedRects = new List<Rect>();

        foreach (Rect rect in rects)
        {
            if (rect.Overlaps(sweepRect))
                containedRects.Add(rect);
        }

        // Remove found rects from original list
        foreach (Rect rect in containedRects)
            rects.Remove(rect);

        // Sort found rects by x position
        containedRects.Sort((a, b) => a.x.CompareTo(b.x));

        return containedRects;
    }
    #endregion

    #region  导出 png文件

    // public Sprite spriteToExport;
    // public Rect rectToExport;
    private void ExportSpriteRectToPNG(Texture2D texture, Rect rectToExport, int index)
    {
        if (texture == null)
        {
            Debug.LogError("要导出的源Texture2D为空!");
            return;
        }
        // 计算裁剪区域在Texture2D中的实际坐标
        int x = (int)rectToExport.x;
        int y = (int)rectToExport.y;
        int width = (int)rectToExport.width;
        int height = (int)rectToExport.height;

        // 创建新的Texture2D对象,用于存储裁剪后的像素数据
        Texture2D outputTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
        Color[] pixels = texture.GetPixels(x, y, width, height);
        outputTexture.SetPixels(pixels);
        outputTexture.Apply();

        // 编码为PNG格式
        byte[] pngData = outputTexture.EncodeToPNG();

        // 保存文件
        if (pngData != null)
        {

            // string filenameNoExtension = Path.GetFileNameWithoutExtension('origonPath');
            File.WriteAllBytes(savePath + "/" + texture.name + '_' + index + ".png", pngData);
        }
        else
        {
            Debug.LogError("无法将" + savePath + texture.name + '_' + index + ".png" + "编码为PNG文件!");
        }
    }
    #endregion

}
#endif

演示:

相关推荐
大飞pkz4 小时前
【Unity】使用XLua进行热修复
unity·c#·游戏引擎·lua·游戏开发·xlua·lua热修复
Leoysq8 小时前
为 Unity 项目添加自定义 USB HID 设备支持 (适用于 PC 和 Android/VR)-任何手柄、无人机手柄、摇杆、方向盘
android·unity·vr
一个程序员(●—●)11 小时前
Unity的HTTP请求类使用方法+Unity整合接口
网络·unity
XR技术研习社15 小时前
“情况说明“以后,Unity XR 开发者如何选择?
unity·游戏引擎·xr
虾球xz17 小时前
游戏引擎学习第257天:处理一些 Win32 相关的问题
c++·学习·游戏引擎
夜猫逐梦19 小时前
【Unity】 组件库分类详解
unity·游戏引擎
Magnum Lehar19 小时前
ApophisZerg的vulkan游戏引擎的实现
游戏引擎
虾球xz19 小时前
游戏引擎学习第255天:构建配置树
c++·学习·游戏引擎
工藤新一¹1 天前
C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 20)
c++·单例模式·游戏引擎·sdl·c++游戏开发