Search code examples
c#unity-game-enginetexturessprite

Resizing a sprite by adding transparent pixels


The reason I wish to do so is that Unity has a nice DTX5 format that reduces the file size by a lot. But to get that, I need a sprite that's size is - both for height and width - a multiple of 4. So I thought I create a new texture with the desired size, load its pixels with the original's pixels and make a sprite out of it that I save as an asset. The issue is that while saving the texture works, I get the same texture with the proper sizes, saving the sprite doesn't work. It spits out something, but that isn't even close to what I need.

Here is the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ResizeSprites
{
    public void Resize(Sprite sprite)
    {
        int _hei, _wid;
        //getting the closest higher values that are a multiple of 4. 
        for (_hei = sprite.texture.height; _hei % 4 != 0; _hei++) ;
        for (_wid = sprite.texture.width; _wid % 4 != 0; _wid++) ;
        //creating the new texture. 
        Texture2D tex = new Texture2D(_wid, _hei,TextureFormat.RGBA32,false);
        //tex.alphaIsTransparency = true;
        //tex.EncodeToPNG();

       //giving the new texture the "improper" ratio sprite texture's pixel info
        //pixel by pixel.
        for (int wid = 0; wid < sprite.texture.width; wid++)
        {
            for (int hei = 0; hei < sprite.texture.height; hei++)
            {
                tex.SetPixel(wid, hei, sprite.texture.GetPixel(wid, hei));
            }
        }
        //saving the asset. the save works, was used for both meshes as well as textures. 
        Sprite n_spr = Sprite.Create(tex,
            new Rect(0, 0, tex.width, tex.height),
            new Vector2(0.5f, 0.5f), 100.0f);
        AssetSaver.CreateAsset(n_spr, sprite.name + "_dtx5");
    }

}

And here are my results:

original sprite

the sad outcome

The first one is the original sprite, and the second is what I was given.

Edit: Even if I don't save my creation, just instantiate it as a GameObject, the result is still the same ugly one.


Solution

  • You really don't need all these code.Texture2D has a resize function so just pull the Texture2D from the Sprite then call the re-szie function to re-size it. That's it.

    Something like this:

    public void Resize(Sprite sprite)
    {
        Texture2D tex = sprite.texture;
    
        tex.Resize(100, 100, TextureFormat.RGBA32, false);
    
        Sprite n_spr = Sprite.Create(tex,
            new Rect(0, 0, tex.width, tex.height),
            new Vector2(0.5f, 0.5f), 100.0f);
    
        AssetSaver.CreateAsset(n_spr, sprite.name + "_dtx5");
    }
    

    As for you original problem, that's because you did not call the Apply function. Each time you modify the pixels, you are supposed to call the Apply function. Finally, always use GetPixels32 not GetPixel or GetPixels. The reason is because GetPixels32 is extremely faster than the rest of the function.

    public void Resize(Sprite sprite)
    {
        int _hei, _wid;
        //getting the closest higher values that are a multiple of 4. 
        for (_hei = sprite.texture.height; _hei % 4 != 0; _hei++) ;
        for (_wid = sprite.texture.width; _wid % 4 != 0; _wid++) ;
        //creating the new texture. 
        Texture2D tex = new Texture2D(_wid, _hei, TextureFormat.RGBA32, false);
        //tex.alphaIsTransparency = true;
        //tex.EncodeToPNG();
    
        //giving the new texture the "improper" ratio sprite texture's pixel info
        //pixel by pixel.
    
        Color32[] color = sprite.texture.GetPixels32();
    
        tex.SetPixels32(color);
    
        tex.Apply();
    
        //saving the asset. the save works, was used for both meshes as well as textures. 
        Sprite n_spr = Sprite.Create(tex,
            new Rect(0, 0, tex.width, tex.height),
            new Vector2(0.5f, 0.5f), 100.0f);
        AssetSaver.CreateAsset(n_spr, sprite.name + "_dtx5");
    }