Last active
May 18, 2023 02:59
-
-
Save fanhexin/824fbee964e80707e4fd95101103794b to your computer and use it in GitHub Desktop.
Keep only the four corners of the nine-patch image and combine them into a small image.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.IO; | |
using UnityEngine; | |
using UnityEditor; | |
public static class ClipNinePatch | |
{ | |
[MenuItem("Assets/Clip Nine Patch", true)] | |
static bool ValidateClipNinePatchImage() | |
{ | |
Texture2D texture = Selection.activeObject as Texture2D; | |
if (texture == null) | |
{ | |
return false; | |
} | |
string path = AssetDatabase.GetAssetPath(texture); | |
TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; | |
if (importer == null || importer.textureType != TextureImporterType.Sprite) | |
{ | |
return false; | |
} | |
return true; | |
} | |
[MenuItem("Assets/Clip Nine Patch")] | |
static void ClipNinePatchImage() | |
{ | |
Texture2D texture = Selection.activeObject as Texture2D; | |
if (texture == null) | |
{ | |
EditorUtility.DisplayDialog("Select Texture", "You must select a texture first!", "OK"); | |
return; | |
} | |
string path = AssetDatabase.GetAssetPath(texture); | |
TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; | |
if (importer == null) | |
{ | |
EditorUtility.DisplayDialog("Import Texture", "Failed to import texture: " + path, "OK"); | |
return; | |
} | |
bool originalIsReadable = importer.isReadable; | |
if (!originalIsReadable) | |
{ | |
// Make texture readable temporarily | |
TextureImporter tmpImporter = AssetImporter.GetAtPath(path) as TextureImporter; | |
tmpImporter.isReadable = true; | |
AssetDatabase.ImportAsset(path); | |
importer = tmpImporter; | |
} | |
var border = importer.spriteBorder; | |
// Calculate new texture size | |
// x left z right w top y bottom | |
int newWidth = (int) (border.x + border.z); | |
if (newWidth == 0) | |
{ | |
newWidth = texture.width; | |
} | |
int newHeight = (int) (border.w + border.y); | |
if (newHeight == 0) | |
{ | |
newHeight = texture.height; | |
} | |
// Create new texture and fill with transparent pixels | |
Texture2D clippedTexture = new Texture2D(newWidth, newHeight, TextureFormat.RGBA32, false); | |
// The lower left corner is (0, 0) | |
// Copy corner pixels to new texture | |
// top left corner | |
Color[] cornerPixels; | |
if (border.x * border.w > 0) | |
{ | |
cornerPixels = texture.GetPixels(0, (int) (texture.height - border.w), (int) border.x, (int) border.w); | |
clippedTexture.SetPixels(0, (int) (newHeight - border.w), (int) border.x, (int) border.w, cornerPixels); | |
} | |
// top right corner | |
if (border.z * border.w > 0) | |
{ | |
cornerPixels = texture.GetPixels((int) (texture.width - border.z), (int) (texture.height - border.w), | |
(int) border.z, (int) border.w); | |
clippedTexture.SetPixels((int) (newWidth - border.z), (int) (newHeight - border.w), (int) border.z, | |
(int) border.w, cornerPixels); | |
} | |
// bottom left corner | |
if (border.x * border.y > 0) | |
{ | |
cornerPixels = texture.GetPixels(0, 0, (int) border.x, (int) border.y); | |
clippedTexture.SetPixels(0, 0, (int) border.x, (int) border.y, cornerPixels); | |
} | |
// bottom right corner | |
if (border.z * border.y > 0) | |
{ | |
cornerPixels = texture.GetPixels((int) (texture.width - border.z), 0, (int) border.z, (int) border.y); | |
clippedTexture.SetPixels((int) (newWidth - border.z), 0, (int) border.z, (int) border.y, cornerPixels); | |
} | |
// without top and bottom | |
if (border.x + border.y > 0 && border.w + border.y == 0) | |
{ | |
cornerPixels = texture.GetPixels(0, 0, (int) border.x, newHeight); | |
clippedTexture.SetPixels(0, 0, (int) border.x, newHeight, cornerPixels); | |
cornerPixels = texture.GetPixels((int) (texture.width - border.z), 0, (int) border.z, newHeight); | |
clippedTexture.SetPixels((int) (newWidth - border.z), 0, (int) border.z, newHeight, cornerPixels); | |
} | |
// without left and right | |
if (border.x + border.z == 0 && border.w + border.y > 0) | |
{ | |
cornerPixels = texture.GetPixels(0, 0, newWidth, (int) border.y); | |
clippedTexture.SetPixels(0, 0, newWidth, (int) border.y, cornerPixels); | |
cornerPixels = texture.GetPixels(0, (int) (texture.height - border.w), newWidth, (int) border.w); | |
clippedTexture.SetPixels(0, (int) (newHeight - border.w), newWidth, (int) border.w, cornerPixels); | |
} | |
// Apply changes to new texture and save as a new asset | |
clippedTexture.Apply(); | |
importer.isReadable = originalIsReadable; | |
AssetDatabase.ImportAsset(path); | |
string defaultPath = Path.GetDirectoryName(path); | |
string fileExtension = Path.GetExtension(path)?.Substring(1); | |
if (string.IsNullOrEmpty(fileExtension)) | |
{ | |
EditorUtility.DisplayDialog("Error", $"Unsupported file extension: {fileExtension}", "OK"); | |
return; | |
} | |
string newPath = EditorUtility.SaveFilePanel("Save Clipped Texture", defaultPath, | |
$"{texture.name}_clipped.{fileExtension}", fileExtension); | |
if (string.IsNullOrEmpty(newPath)) | |
{ | |
EditorUtility.DisplayDialog("Error", "Failed to save clipped texture: path is empty", "OK"); | |
return; | |
} | |
byte[] bytes; | |
switch (fileExtension) | |
{ | |
case "png": | |
bytes = clippedTexture.EncodeToPNG(); | |
break; | |
case "jpg": | |
bytes = clippedTexture.EncodeToJPG(); | |
break; | |
case "tga": | |
bytes = clippedTexture.EncodeToTGA(); | |
break; | |
case "exr": | |
bytes = clippedTexture.EncodeToEXR(); | |
break; | |
default: | |
EditorUtility.DisplayDialog("Error", $"Unsupported file extension: {fileExtension}", "OK"); | |
return; | |
} | |
File.WriteAllBytes(newPath, bytes); | |
AssetDatabase.Refresh(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment