Angelsm
Angelsm

Reputation: 339

Show images downloaded from a server in a fast way

I have a scene where I'd like to show multiple images downloaded from a server. I'm trying to download the textures and store them in a List. When the for loop finish running, I sort the List by name and then I instantiate the RawImage from the List, but doesn't works. What am I doing wrong?

public GameObject contentRef;
public RawImage imgPrefab;

void Start()
{
    StartCoroutine(DownloadtheFiles());
}

public IEnumerator DownloadtheFiles()
{
    yield return null;

    List<string> photolist = ES2.LoadList<string>("myPhotos.txt");

    for (int i = 0; i < photolist.Count; i++)
    {
        //Don't capture i variable
        int index = i;

        bool reqDone = false;

        new GetUploadedRequest()

            .SetUploadId(photolist[index])
            .Send((response) =>
                {
                    StartCoroutine(DownloadImages(response.Url, index,
                        (status) => { reqDone = status; }));


                    //return null;
                });

        //Wait in the for loop until the current request is done
        while (!reqDone)
            yield return null;
    }
}

public IEnumerator DownloadImages(string downloadUrl, int index, Action<bool> done)
{
    var www = new WWW(downloadUrl);
    yield return www;

    //Get the downloaded image
    Texture2D tex = new Texture2D(4, 4);
    www.LoadImageIntoTexture(tex);

    List <Texture2D> texList = new List <Texture2D> ();

    for (int i = 0; i < tex.Count; i++)
    {
        texList.Add (tex);
    }

    texList = texList.OrderBy(mtex => mtex.name).ToList();

    for (int i = 0; i < tex.Count; i++)
    {
        RawImage newImg = Instantiate(imgPrefab, contentRef.transform);
        //Change the name
        newImg.name = "Image-" + index;
        //Apply the downloaded image
        newImg.texture = tex;
    }

    //Done
    if (done != null)
        done(true);
}

}

Upvotes: 1

Views: 168

Answers (1)

Programmer
Programmer

Reputation: 125305

Your RawImage code should be done outside the DownloadImages function because DownloadImages is called to download image from the url in the for loop. The RawImage instantiation should be done only after the for loop has completed.

Also, using texList.OrderBy(mtex => mtex.name).ToList(); wouldn't work because your string contains both string and int and is in this format "Image-" + 0;". You will need a custom function to do that by splitting the string and int then sorting with the int.

Finally, after the for loop has finished running, you need a way to determine that all images has finished downloading before instantiating the RawImages. You can do this by using array or List of bool with the size of the List<string> photolist that contains the link of images to download. Pass that array of bool to the DownloadImages and use the index argument to set it to true when each download is done.

public GameObject contentRef;
public RawImage imgPrefab;

List<Texture2D> downloadedTextures = new List<Texture2D>();

void Start()
{
    DownloadtheFiles();
}

public void DownloadtheFiles()
{

    List<string> photolist = ES2.LoadList<string>("myPhotos.txt");

    //Used to determine when were done downloading
    bool[] doneDownloading = new bool[photolist.Count];

    //Download images only.Don't instantiate anything
    for (int i = 0; i < photolist.Count; i++)
    {
        //Don't capture i variable
        int index = i;

        new GetUploadedRequest()

            .SetUploadId(photolist[index])
            .Send((response) =>
            {
                StartCoroutine(DownloadImages(response.Url, index, doneDownloading));
            });
    }

    //Instantiate the download images
    StartCoroutine(InstantiateImages(doneDownloading));
}

//Instantiates the downloaded images after they are done downloading
IEnumerator InstantiateImages(bool[] downloadStatus)
{
    //Wait until all images are done downloading
    for (int i = 0; i < downloadStatus.Length; i++)
    {
        while (!downloadStatus[i])
            yield return null;
    }

    //Sort the images by string
    sort(ref downloadedTextures);

    //Now, instantiate the images
    for (int i = 0; i < downloadedTextures.Count; i++)
    {
        //Instantiate the image prefab GameObject and make it a child of the contentRef
        RawImage newImg = Instantiate(imgPrefab, contentRef.transform);

        //Apply the downloaded image
        newImg.texture = downloadedTextures[i];

        //Update name so that we can see the names in the Hierarchy
        newImg.name = downloadedTextures[i].name;
    }

    //Clear List for next use
    downloadedTextures.Clear();
}

//Sort the downloaded Textures by name
void sort(ref List<Texture2D> targetList)
{
    var ordered = targetList.Select(s => new { s, Str = s.name, Split = s.name.Split('-') })
    .OrderBy(x => int.Parse(x.Split[1]))
    .ThenBy(x => x.Split[0])
    .Select(x => x.s)
    .ToList();

    targetList = ordered;
}

public IEnumerator DownloadImages(string downloadUrl, int index, bool[] downloadStatus)
{
    //Download image
    var www = new WWW(downloadUrl);
    yield return www;

    //Get the downloaded image and add it to the List
    Texture2D tex = new Texture2D(4, 4);
    //Change the name
    tex.name = "Image-" + index;
    www.LoadImageIntoTexture(tex);
    downloadedTextures.Add(tex);

    downloadStatus[index] = true;
}

Upvotes: 1

Related Questions