[Unity (C #)] Save related data together with image data

3 minute read

Introduction

[Unity (C #)] Convert texture to image data, save and load in terminal
↑ It is a continuation of the last time.

This time, I would like to add character string information to the saved image data and save it.

Way of thinking

Define a structure with an image and a string as one chunk.
Save the structure as Json format.
Deserialize the structure when loading.

構造体.png

code

The code structure is as follows.
① Structure
② Json conversion Utility class
③ Class to save and load the structure


Structure

First, define the structure.
Since the binary data of the image is written with File.WriteAllBytes
The data to be given to the structure is the path where the image data is saved.

using System;

/// <summary>
///Image data structure
/// </summary>
[Serializable]
public struct ImageData
{
    /// <summary>
    ///Image save destination path
    /// </summary>
    public string ImageSavePath;

    /// <summary>
    ///Image name
    /// </summary>
    public string ImageName;

    /// <summary>
    ///constructor
    /// </summary>
    /// <param name="imageSavePath">Destination path</param>
    /// <param name="imageName">Saved name</param>
    public ImageData(string imageSavePath,string imageName)
    {
        this.ImageSavePath = imageSavePath;
        this.ImageName = imageName;
    }
}

Json conversion Utility class

Next, define a class that converts the structure to Json format.
[Reference link]: [Unity (C #)] Implementation of save and load using JsonUtility

using System;
using System.IO;
using UnityEngine;

/// <summary>
///Implementation of Save and Load functions
/// </summary>
public static class JsonDataUtility
{
    /// <summary>
    ///Write function
    /// </summary>
    /// <param name="imageData">Data to serialize</param>
    public static void Save(ImageData imageData,string path)
    {
        //Serialize execution
        string jsonSerializedData = JsonUtility.ToJson(imageData);
        Debug.Log(jsonSerializedData);

        //Actually create a file and write
        using (var sw = new StreamWriter (path, false)) 
        {
            try
            {
                //Write to file
                sw.Write (jsonSerializedData);
            }
            catch (Exception e) //What to do when it fails
            {
                Debug.Log (e);
            }
        }
    }

    /// <summary>
    ///Read function
    /// </summary>
    /// <returns>Deserialized structure</returns>
    public static ImageData Load(string path)
    {
        ImageData jsonDeserializedData = new ImageData();

        try 
        {
            //Read the file
            using (FileStream fs = new FileStream (path, FileMode.Open))
            using (StreamReader sr = new StreamReader (fs)) 
            {
                string result = sr.ReadToEnd ();
                Debug.Log(result);

                //Put the read Json in the structure
                jsonDeserializedData = JsonUtility.FromJson<ImageData>(result);
            }
        }
        catch (Exception e) //What to do when it fails
        {
            Debug.Log (e);
        }

        //Returns a deserialized struct
        return jsonDeserializedData;
    }
}

Class to save and load structs

A class that saves and loads structures.
I’m doing a lot of other things, but it’s a sample, so I’m happy with it.

using System.IO;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
///Save and load structs
/// </summary>
public class UseStructData : MonoBehaviour
{
    [SerializeField] private Button _saveButton;
    [SerializeField] private Button _loadButton;
    [SerializeField] private Button _resetButton;
    [SerializeField] private InputField _inputField;
    [SerializeField] private Text _inputText;
    [SerializeField] private Text _loadText;
    [SerializeField] private Image _paintImage;
    [SerializeField] private Image _loadImage;
    [SerializeField] private Painter _painter;

    private const string IMAGE_SAVE_FOLDER = "Image";
    private const string IMAGE_DATA_SAVE_FOLDER = "ImageData";
    private const string PNG = ".png ";
    private const string JSON = ".json";
    
    ///  /// <summary>
    ///Get the save destination path
    /// </summary>
    /// <param name="folderName">Delimited folder name</param>
    /// <returns>Destination path</returns>
    private string GetSavePath(string folderName,string fileName,string type)
    {
        string directoryPath = Application.persistentDataPath + "/" + folderName + "/";
        
        if (!Directory.Exists(directoryPath))
        {
            //Create if it doesn't exist yet
            Directory.CreateDirectory(directoryPath);
            return directoryPath + fileName + type;
        }

        return directoryPath + fileName + type;
    }

    private void Start()
    {
        //Save button
        _saveButton.OnPointerClickAsObservable().Subscribe(_ =>
            {
                SaveImageData("SoftCream");
                
                //reset
                _painter.ResetTexture();
                _inputField.text = "";
            })
            .AddTo(this);
        //Load button
        _loadButton.OnPointerClickAsObservable().Subscribe(_ => LoadImageData("SoftCream")).AddTo(this);
        //Reset button
        _resetButton.OnPointerClickAsObservable().Subscribe(_ => _painter.ResetTexture()).AddTo(this);;
    }

    /// <summary>
    ///Serialize the structure
    /// </summary>
    private void SaveImageData(string fileName)
    {
        string pngPath = GetSavePath(IMAGE_SAVE_FOLDER, fileName, PNG);
        string jsonPath = GetSavePath(IMAGE_DATA_SAVE_FOLDER, fileName, JSON);
        
        //Enter the path and name in the structure.
        ImageData imageData =new ImageData(pngPath,_inputText.text);
        //Convert to png
        byte[] bytes = _paintImage.sprite.texture.EncodeToPNG();
        //Save
        File.WriteAllBytes(pngPath, bytes);
        //Convert struct to Json
        JsonDataUtility.Save(imageData,jsonPath);
    }

    /// <summary>
    ///Convert & load to texture
    /// </summary>
    private void LoadImageData(string fileName)
    {
        string jsonPath = GetSavePath(IMAGE_DATA_SAVE_FOLDER, fileName, JSON);
        ImageData imageData = JsonDataUtility.Load(jsonPath);
        //Read
        byte[] bytes = File.ReadAllBytes(imageData.ImageSavePath);
        //Convert image to texture
        Texture2D loadTexture = new Texture2D(2, 2);
        loadTexture.LoadImage(bytes);
        //Convert textures to sprites
        _loadImage.sprite = Sprite.Create(loadTexture, new Rect(0, 0, loadTexture.width, loadTexture.height), Vector2.zero);
        //Show the name of the image
        _loadText.text = imageData.ImageName;
    }
}

Directory.Exists
The method of creating a new directory and using it as the save destination path has become sober.
Check if the directory exists with Directory.Exists
I got an error if I didn’t prepare the branch process.

        if (!Directory.Exists(directoryPath))
        {
            //Create if it doesn't exist yet
            Directory.CreateDirectory(directoryPath);
            return directoryPath + fileName + type;
        }

demo

Save the elegant illustration and the character string you entered as the name of the illustration,
I succeeded in reading.

Qiita画像保存2.gif