Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save images on mobile from online source unity

Main Goal : Load images from an online url then save the image (whatever type) locally in a /Repo/{VenueName} dir on a mobile. This way it will hopefully save on future mobile data, when scene loads checks for local image first then calls a www request if it doesn't exist on the mobile already.

I've got images online, I've pulled the url from a json file and now I want to store them locally on mobile devices to save data transfer for the end user.

I've gone round in circles with persistent data paths and IO.directories and keep hitting problems.

At the moment I've got a function that saves text from online and successfully stores it on a device but if I use it for images it won't work due to the string argument shown below, I tried to convert it to bytes editing the function too rather than passing it www.text and got an image corrupt error.

Here's the old function I use for text saving files.

public void writeStringToFile( string str, string filename ){
        #if !WEB_BUILD
            string path = pathForDocumentsFile( filename );
            FileStream file = new FileStream (path, FileMode.Create, FileAccess.Write);

            StreamWriter sw = new StreamWriter( file );
            sw.WriteLine( str );

            sw.Close();
            file.Close();
        #endif  
    }


public string pathForDocumentsFile( string filename ){ 
        if (Application.platform == RuntimePlatform.IPhonePlayer)
        {
            string path = Application.dataPath.Substring( 0, Application.dataPath.Length - 5 );
            path = path.Substring( 0, path.LastIndexOf( '/' ) );
            return Path.Combine( Path.Combine( path, "Documents" ), filename );
        }else if(Application.platform == RuntimePlatform.Android){
        string path = Application.persistentDataPath;   
            path = path.Substring(0, path.LastIndexOf( '/' ) ); 
            return Path.Combine (path, filename);
        }else {
            string path = Application.dataPath; 
            path = path.Substring(0, path.LastIndexOf( '/' ) );
            return Path.Combine (path, filename);
        }
    }

This works well for text as it expect a string but I can't get it working on images no matter how much I edit it.

I ended up going down a different route but have unauthorised access issues with the following code and don't think it will work on mobiles but..

IEnumerator loadPic(WWW www, string thefile, string folder)
 {
    yield return www;
     string venue = Application.persistentDataPath + folder;
     string path = Application.persistentDataPath + folder + "/" + thefile;

    if (!System.IO.Directory.Exists(venue))
     {
        System.IO.Directory.CreateDirectory(venue);
     }

    if (!System.IO.Directory.Exists(path))
     {
        System.IO.Directory.CreateDirectory(path);
     }

    System.IO.File.WriteAllBytes(path, www.bytes);
 }

Urgh, it's 3am here and I can't figure it out, can you wizards help me out? Thanks in advance.

like image 261
Diego Avatar asked Apr 15 '17 01:04

Diego


1 Answers

I tried to convert it to bytes editing the function too rather than passing it www.text and got an image corrupt error

That's probably the cause of 90% of your problem. WWW.text is used for non binary data such as simple text.

1.Download images or files with WWW.bytes not WWW.text.

2.Save image with File.WriteAllBytes.

3.Read image with File.ReadAllBytes.

4.Load image to Texture with Texture2D.LoadImage(yourImageByteArray);

5.Your path must be Application.persistentDataPath/yourfolderName/thenFileName if you want this to be compatible with every platform. It shouldn't be Application.persistentDataPath/yourFileName or Application.dataPath.

6.Finally, use Debug.Log to see what's going on in your code. You must or at-least use the debugger. You need to know exactly where your code is failing.

You still need to perform some error checking stuff.

public void downloadImage(string url, string pathToSaveImage)
{
    WWW www = new WWW(url);
    StartCoroutine(_downloadImage(www, pathToSaveImage));
}

private IEnumerator _downloadImage(WWW www, string savePath)
{
    yield return www;

    //Check if we failed to send
    if (string.IsNullOrEmpty(www.error))
    {
        UnityEngine.Debug.Log("Success");

        //Save Image
        saveImage(savePath, www.bytes);
    }
    else
    {
        UnityEngine.Debug.Log("Error: " + www.error);
    }
}

void saveImage(string path, byte[] imageBytes)
{
    //Create Directory if it does not exist
    if (!Directory.Exists(Path.GetDirectoryName(path)))
    {
        Directory.CreateDirectory(Path.GetDirectoryName(path));
    }

    try
    {
        File.WriteAllBytes(path, imageBytes);
        Debug.Log("Saved Data to: " + path.Replace("/", "\\"));
    }
    catch (Exception e)
    {
        Debug.LogWarning("Failed To Save Data to: " + path.Replace("/", "\\"));
        Debug.LogWarning("Error: " + e.Message);
    }
}

byte[] loadImage(string path)
{
    byte[] dataByte = null;

    //Exit if Directory or File does not exist
    if (!Directory.Exists(Path.GetDirectoryName(path)))
    {
        Debug.LogWarning("Directory does not exist");
        return null;
    }

    if (!File.Exists(path))
    {
        Debug.Log("File does not exist");
        return null;
    }

    try
    {
        dataByte = File.ReadAllBytes(path);
        Debug.Log("Loaded Data from: " + path.Replace("/", "\\"));
    }
    catch (Exception e)
    {
        Debug.LogWarning("Failed To Load Data from: " + path.Replace("/", "\\"));
        Debug.LogWarning("Error: " + e.Message);
    }

    return dataByte;
}

Usage:

Prepare url to download image from and save to:

//File url
string url = "http://www.wallpapereast.com/static/images/Cool-Wallpaper-11C4.jpg";
//Save Path
string savePath = Path.Combine(Application.persistentDataPath, "data");
savePath = Path.Combine(savePath, "Images");
savePath = Path.Combine(savePath, "logo");

As you can see, there is no need to add the image extension(png, jpg) to the savePath and you shouldn't add the image extension in the save path. This will make it easier to load later on if you don't know the extension. It should work as long as the image is a png or jpg image format.

Dowload file:

downloadImage(url, savePath);

Load Image from file:

byte[] imageBytes = loadImage(savePath);

Put image to Texture2D:

Texture2D texture;
texture = new Texture2D(2, 2);
texture.LoadImage(imageBytes);
like image 144
Programmer Avatar answered Sep 21 '22 06:09

Programmer