Skip to content

Instantly share code, notes, and snippets.

@Hotrian
Last active July 13, 2018 08:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hotrian/e453948223cc8101fd1fabdbaa8289b3 to your computer and use it in GitHub Desktop.
Save Hotrian/e453948223cc8101fd1fabdbaa8289b3 to your computer and use it in GitHub Desktop.
Automatically Scales Sprite Texture2Ds, allowing you to multiply the image size safely, and effectively. Not guaranteed to work on every Sprite, or at all for that matter :P.
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
/* Unity Sprite Resizer v1.6 © Hotrian 2017
*
* This has only been tested on PNG files.
*
* Usage instructions:
* 1. Put SpriteResizer.cs at
* ..\Assets\Editor\SpriteResizer.cs
* 2. After Unity recompiles, at the top Click Window > SpriteResizer
* 3. In the SpriteResizer window, select your Sprite's Texture2D
* 4. Select a Multiplier value
* 5. Click Upscale Texture
*
* This generates replacements for your Sprite, but cannot install them automatically as they are locked by Unity.
* Your replacement files will be named:
* [originalName.png2]
* [originalName.png.meta2]
*
* To install your new sprite:
* 1. First, make sure Unity is closed so it is not locking your assets
* 2. Navigate to your Sprite in File Explorer
* 3. Delete the [originalName.png] and [originalName.png.meta] files
* 4. Rename the new files by removing the 2 that has been added after the extension:
* [originalName.png2] -> [originanName.png]
* [originalName.png.meta2] -> [originanName.png.meta]
* 5. Restart Unity and Marvel!
*
*/
public class SpriteResizer : EditorWindow
{
private Texture2D _tex;
private Powers _multiplier = Powers.Two;
[MenuItem("Window/SpriteResizer")]
public static void ShowWindow()
{
EditorWindow.GetWindow(typeof(SpriteResizer));
}
void OnGUI()
{
_tex = (Texture2D)EditorGUILayout.ObjectField("Sprite", _tex, typeof(Texture2D), false);
if (_tex == null) return;
var w1 = _tex.width;
var w2 = _tex.width * (int)_multiplier;
var h1 = _tex.height;
var h2 = _tex.height * (int)_multiplier;
_multiplier = (Powers)EditorGUILayout.EnumPopup("Multiplier:", _multiplier);
GUILayout.Label(string.Format("Width:\t({0})\t{1}\nHeight:\t({2})\t{3}", w1, w2, h1, h2), EditorStyles.boldLabel);
if (GUILayout.Button("Upscale Texture"))
{
// Generate some information about this action
var path = AssetDatabase.GetAssetPath(_tex);
var filePath = Application.dataPath + path.Substring(6);
var metaPath = Application.dataPath + path.Substring(6) + ".meta";
var file = path.LastIndexOf(System.IO.Path.DirectorySeparatorChar);
if (file == -1) file = path.LastIndexOf(System.IO.Path.AltDirectorySeparatorChar);
if (file == -1) Debug.LogWarning("Couldn't find last Path Seperator");
var fileName = path.Substring(file + 1);
try
{
_tex.GetPixels();
}
catch (UnityException e)
{
if (e.Message.Contains("' is not readable, the texture memory can not be accessed from scripts."))
{
Debug.LogWarning("Texture [" + fileName + "] is not readable.. Doing this the hard way..");
_tex = LoadPng(filePath);
}
else
{
Debug.LogException(e);
return;
}
}
// Attempt to save the resized texture to disk
Debug.LogWarning("Resizing Texture [" + fileName + "]");
System.IO.File.WriteAllBytes(filePath + "2", Resize(_tex, (int)_multiplier).EncodeToPNG());
Debug.LogWarning("Resized. Fixing Sprite Meta...");
// Parse the Metadata file
var lines = System.IO.File.ReadAllLines(metaPath);
var newLines = new List<string>();
foreach (var line in lines)
{
// Handles resizing the Pixels Per Unit
if (line.TrimStart().StartsWith("spritePixelsToUnits: "))
{
var len = line.IndexOf("spritePixelsToUnits: ", StringComparison.CurrentCulture);
var baseVal = int.Parse(line.Substring(len + 21).Trim());
switch (baseVal)
{
case 1:
case 4:
case 8:
case 16:
case 32:
case 64:
case 128:
case 256:
case 512:
case 1024:
break;
default:
Debug.LogWarning("Pixels Per Unit should be a Power of 2! Current value: " + baseVal);
break;
}
var val = baseVal * (int)_multiplier;
newLines.Add(line.Substring(0, len + 21) + val);
} // Handles resizing sliced Sprite X
else if (line.TrimStart().StartsWith("x: "))
{
var len = line.IndexOf("x: ", StringComparison.CurrentCulture);
var val = int.Parse(line.Substring(len + 3).Trim()) * (int)_multiplier;
newLines.Add(line.Substring(0, len + 3) + val);
} // Handles resizing sliced Sprite Y
else if (line.TrimStart().StartsWith("y: "))
{
var len = line.IndexOf("y: ", StringComparison.CurrentCulture);
var val = int.Parse(line.Substring(len + 3).Trim()) * (int)_multiplier;
newLines.Add(line.Substring(0, len + 3) + val);
} // Handles resizing sliced Sprite Width
else if (line.TrimStart().StartsWith("width: "))
{
var len = line.IndexOf("width: ", StringComparison.CurrentCulture);
var val = int.Parse(line.Substring(len + 7).Trim()) * (int)_multiplier;
newLines.Add(line.Substring(0, len + 7) + val);
} // Handles resizing sliced Sprite Height
else if (line.TrimStart().StartsWith("height: "))
{
var len = line.IndexOf("height: ", StringComparison.CurrentCulture);
var val = int.Parse(line.Substring(len + 8).Trim()) * (int)_multiplier;
newLines.Add(line.Substring(0, len + 8) + val);
} // Add all other lines verbatim
else newLines.Add(line);
}
// Attempt to save the new metadata to disk
try
{
System.IO.File.WriteAllLines(metaPath + "2", newLines.ToArray());
}
catch (Exception e)
{
Debug.LogException(e);
return;
}
Debug.Log("Texture Resized Successfully!");
Debug.Log(string.Format("Please close Unity, then delete [{0}] and [{1}], and rename [{2}] and [{3}] to replace them.", fileName, fileName + ".meta", fileName + "2", fileName + ".meta2"));
}
}
public static Texture2D LoadPng(string filePath)
{
if (!System.IO.File.Exists(filePath)) return null;
var fileData = System.IO.File.ReadAllBytes(filePath);
var tex = new Texture2D(2, 2) {filterMode = FilterMode.Point};
tex.LoadImage(fileData); //..this will auto-resize the texture dimensions.
return tex;
}
/// <summary>
/// Scale a given texture to a larger multiple of the same texture
/// </summary>
Texture2D Resize(Texture2D t, int scale)
{
// Generate a Point Filtered texture which is [scale] times larger than the source Texture2D
var tex = new Texture2D(t.width * scale, t.height * scale, t.format, false) { filterMode = FilterMode.Point };
var c = t.GetPixels(); // Get the pixel data for the source texture
var cExpand = new Color[c.Length * scale * scale]; // Create an array to store our working data
var i = 0;
var j = 0;
// Run through every line of the source texture
for (var h = 0; h < t.height; h++)
{
var lJ = j;
// Repeat this line [scale] number of times
for (var y = 0; y < scale; y++)
{
j = lJ;
// Run through every column of the source texture
for (var w = 0; w < t.width; w++)
{
// Repeat this line [scale] number of times
for (var x = 0; x < scale; x++)
{
// Save this color to our working data
cExpand[i] = c[j];
i++;
}
j++;
}
}
}
// Update our new texture with the working data
tex.SetPixels(cExpand);
tex.filterMode = FilterMode.Point;
tex.Apply();
return tex;
}
public enum Powers
{
One = 1, // Effectively does nothing. Duplicates the Texture as is.
Two = 2, // Doubles the Texture size on each axis.
Four = 4, // Quadruples the Texture size on each axis.
Eight = 8, // etc.
Sixteen = 16,
Thirtytwo = 32,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment