Issues Dynamically Creating Sprites and Saving Them

I’ve created an editor script that will dynamically create sprites and save them to my asset folders. It mostly works correctly except that pixelsPerUnit isn’t saving correctly. I determine the appropriate pixelsPerUnit (say in this case it’s 30) but when the sprite is saved it always goes with the default of 100.

While we’re at it, I was having issue saving he texture originally so I just use System.IO and refresh the asset database. This has the undesired consequence that my check for not generated mipmaps is ignored (but less of an issue).

The code for saving the sprite.

void SaveSprite(Texture2D tex)
{
    string assetPath = "Assets/Sprites/ExampleTex.png";

    Sprite sp = Sprite.Create(
        tex, 
        new Rect(0, 0, tex.width, tex.height),
        new Vector2(0, 0), 
        30);

    sp.name = "SpriteName";

    Debug.Log("Saved PPU: " + sp.pixelsPerUnit); // Saved PPU: 30

    // Would prefer a Unity specific way to do this but AssetDatabase.CreateAsset wasn't working.
    // Due to it being a .png instead of .asset?
    File.WriteAllBytes(Application.dataPath + "/../" + assetPath, tex.EncodeToPNG());
    AssetDatabase.Refresh();
    AssetDatabase.AddObjectToAsset(sp, assetPath);
    AssetDatabase.SaveAssets();

    sp = AssetDatabase.LoadAssetAtPath(assetPath, typeof (Sprite)) as Sprite;

    Debug.Log("Loaded PPU: " + s.pixelsPerUnit); // Loaded PPU: 100
}

Thanks in advance!
C.J.

I know it’s been a long time, but I had this same problem today.

Ended up using this to correctly save a sprite keeping its pixelsPerUnit.

Sprite SaveSpriteToEditorPath(Sprite sp,string path) {

        string dir = Path.GetDirectoryName (path);

        Directory.CreateDirectory (dir);

        File.WriteAllBytes(path, sp.texture.EncodeToPNG());
        AssetDatabase.Refresh();
        AssetDatabase.AddObjectToAsset(sp, path);
        AssetDatabase.SaveAssets();

        TextureImporter ti = AssetImporter.GetAtPath (path) as TextureImporter;

        ti.spritePixelsPerUnit = sp.pixelsPerUnit;
        ti.mipmapEnabled = false;
        EditorUtility.SetDirty (ti);
        ti.SaveAndReimport ();

        return  AssetDatabase.LoadAssetAtPath(path, typeof (Sprite)) as Sprite;
    }
6 Likes

I just tried this and I am getting "Unnknown error occured while loading :frowning:
I get the texture encoded created correctly then the rest does not happen

I think AssetDatabase.AddObjectToAsset is supposed to copy the Sprite properties to the created asset, but it’s the source of the “Unnknown error”. Maybe it broke since Miguel-Ferreira’s post. Since that doesn’t work, I also needed to set the texture to use the Sprite type so it can be loaded as a Sprite:

ti.textureType = TextureImporterType.Sprite;

(Just like after dragging a png into the project.)

My function in Unity 2019.4.7 looks like this:

// proj_path should be relative to the Assets folder.
static Sprite SaveSpriteAsAsset(Sprite sprite, string proj_path)
{
    var abs_path = Path.Combine(Application.dataPath, proj_path);
    proj_path = Path.Combine("Assets", proj_path);

    Directory.CreateDirectory(Path.GetDirectoryName(abs_path));
    File.WriteAllBytes(abs_path, ImageConversion.EncodeToPNG(sprite.texture));

    AssetDatabase.Refresh();

    var ti = AssetImporter.GetAtPath(proj_path) as TextureImporter;
    ti.spritePixelsPerUnit = sprite.pixelsPerUnit;
    ti.mipmapEnabled = false;
    ti.textureType = TextureImporterType.Sprite;

    EditorUtility.SetDirty(ti);
    ti.SaveAndReimport();

    return AssetDatabase.LoadAssetAtPath<Sprite>(proj_path);
}