Skip to content

Instantly share code, notes, and snippets.

@fanhexin
Last active May 18, 2023 02:59
Show Gist options
  • Save fanhexin/824fbee964e80707e4fd95101103794b to your computer and use it in GitHub Desktop.
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.
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