DEV Community

loading...

Download Images From a Url Endpoint in Runtime with Unity

cemuka profile image Cem Ugur Karacam ・2 min read

In this tutorial, we will make a GET HTTP method to download an image and use it in the scene. I'll use this 600x600 image from JSONPlaceholder .

First, making a client. Create a script Client.

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class Client : MonoBehaviour
{
    IEnumerator GetTextureRequest(string url)
    {
        using(var www = UnityWebRequestTexture.GetTexture(url))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
            }
            else
            {
                if (www.isDone)
                {
                  //handle the result
                }
            }
        }
      }
}

To make a GET request we need to use UnityEngine.Networking namespace. But, our goal is specifically downloading an image in runtime, unity has some useful api to handle this work. Remaining work is easy, making a sprite from this downloaded texture. Further info on DownloadHandlerTexture here.

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class Client : MonoBehaviour
{
    IEnumerator GetTextureRequest(string url, System.Action<Sprite> callback)
    {
        using(var www = UnityWebRequestTexture.GetTexture(url))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
            }
            else
            {
                if (www.isDone)
                {
                    var texture = DownloadHandlerTexture.GetContent(www);
                    var rect = new Rect(0, 0, 600f, 600f);
                    var sprite = Sprite.Create(texture,rect,new Vector2(0.5f,0.5f));
                    callback(sprite);
                }
            }
        }
      }
}

I've added a second parameter to the method, because since unity coroutines can't return a type, I'll use an Action as a callback here.

To make a sprite, Sprite class provides a Create method that takes a Texture2D argument as the source of sprite, a Rect argument to configure dimensions and a Vector2 to define pivot point for the sprite.

To make it visible on the screen, I need a Sprite object in the scene and a reference it's SpriteRenderer to pass downloaded sprite.

To complete the Client let's call the coroutine in Start.

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class Client : MonoBehaviour
{
    public SpriteRenderer spriteRenderer;

    private Sprite targetSprite;
    private string url = "https://via.placeholder.com/600/92c952";

    private void Start() 
    {
        StartCoroutine(GetTextureRequest(url, (response) => {
            targetSprite = response;
            spriteRenderer.sprite = targetSprite;
        })); 
    }   

    IEnumerator GetTextureRequest(string url, System.Action<Sprite> callback)
    {
        using(var www = UnityWebRequestTexture.GetTexture(url))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
            }
            else
            {
                if (www.isDone)
                {
                    var texture = DownloadHandlerTexture.GetContent(www);
                    var rect = new Rect(0, 0, 600f, 600f);
                    var sprite = Sprite.Create(texture,rect,new Vector2(0.5f,0.5f));
                    callback(sprite);
                }
            }
        }
      }
}

Now, I need some objects in the scene.

Create a Sprite in Hierarchy.

sc1

Next, create another object for Client and make sure that referencing Sprite object's renderer to Client.

sc2

Now it's good to go. Hit to play!

gif

Consider that, it may consume some processing power for multiple files. Here is my profiler result for this single image:

sc3

Discussion (2)

Collapse
gibranixu profile image
GibranIxu • Edited

Your tutorial is great i think it might just save me from a problem i am having.
But i am unable to save the sprite in an array.
Here is the problematic code:

int i = 0;
foreach(string url in collectableUrls){
  StartCoroutine(GetSprites(collectableUrls[i], (response) => {
                                                collectables[i] = response;} ));
  i++;
}

i am doing a foreach loop with an array of links from which i intend to get my sprites, but instead of assigning it inmediatly to a SpriteRenderer i save it in an array of the same size.

The two problems i have are that, 1. Its only saving the last sprite in 'collectableUrls', and 2. 'i' the index in which it should save the sprite array ' collectables' is the length of the array, while it should be one less than the length to prevent IndexOutOfBounds.

I am terribly confused, i want to use this as a generic method because this one method, i think, it should work for a generic string[] i give it and i should be able to save it in a generic sprite[], since i have to get several sprites with different pourpuses.

I got a brute force solution but i dont like it and i rather use a more elegant, shorter and generic code, instead of one IEnumerator coroutine for each array.

if you could point me into a direction it would mean a lot.
Thanks in advance and sorry for the long answer.

Collapse
pythonmas profile image
pythonMas

in case you send a different url to an image file as you should verify that

Forem Open with the Forem app