I quickly created an image “resampler” that always crops around the center. It does a simple bilinear interpolation:
edit
Oh that was unexpected! I just “inlined” all those method calls inside the for loops to improve the performance. The inlined version runs 8 times faster ^^. In my tests i used an 1338x2000 image and let it upscale to 5000x5000. It took about 16 seconds while the optimised version only took about 2 seconds. Well it’s 25 million pixels. To process one pixel it took (on average) 80 nano seconds ^^
I’ve placed the optimised version on my dropbox over here: TextureTools.cs. I keep the unoptimised one here as it’s shorter and easier to understand / follow.
public class TextureTools
{
public static Texture2D ResampleAndCrop(Texture2D source, int targetWidth, int targetHeight)
{
int sourceWidth = source.width;
int sourceHeight = source.height;
float sourceAspect = (float)sourceWidth / sourceHeight;
float targetAspect = (float)targetWidth / targetHeight;
int xOffset = 0;
int yOffset = 0;
float factor = 1;
if (sourceAspect > targetAspect)
{ // crop width
factor = (float)targetHeight / sourceHeight;
xOffset = (int)((sourceWidth - sourceHeight * targetAspect) * 0.5f);
}
else
{ // crop height
factor = (float)targetWidth / sourceWidth;
yOffset = (int)((sourceHeight - sourceWidth / targetAspect) * 0.5f);
}
Color32[] data = source.GetPixels32();
Color32[] data2 = new Color32[targetWidth * targetHeight];
for (int y = 0; y < targetHeight; y++)
{
for (int x = 0; x < targetWidth; x++)
{
var p = new Vector2(Mathf.Clamp(xOffset + x / factor, 0, sourceWidth - 1), Mathf.Clamp(yOffset + y / factor, 0, sourceHeight - 1));
// bilinear filtering
var c11 = data[Mathf.FloorToInt(p.x) + sourceWidth * (Mathf.FloorToInt(p.y))];
var c12 = data[Mathf.FloorToInt(p.x) + sourceWidth * (Mathf.CeilToInt(p.y))];
var c21 = data[Mathf.CeilToInt(p.x) + sourceWidth * (Mathf.FloorToInt(p.y))];
var c22 = data[Mathf.CeilToInt(p.x) + sourceWidth * (Mathf.CeilToInt(p.y))];
var f = new Vector2(Mathf.Repeat(p.x, 1f), Mathf.Repeat(p.y, 1f));
data2[x + y * targetWidth] = Color.Lerp(Color.Lerp(c11, c12, p.y), Color.Lerp(c21, c22, p.y), p.x);
}
}
var tex = new Texture2D(targetWidth, targetHeight);
tex.SetPixels32(data2);
tex.Apply(true);
return tex;
}
}
The important part is the xOffset and yOffset which is half the difference between the original height (or width) and the cropped height (or width). “factor” is the actual “zooming” factor. This method can down scale as well as upscale. You can specify anything as targetsize it simply scales the image so it fits into the target area. Everything that is too large is cropped equally on both ends (either top and bottom or left and right).