{"id":16207556,"url":"https://github.com/ivanmurzak/unity-imageloader","last_synced_at":"2025-04-12T22:37:02.343Z","repository":{"id":186588950,"uuid":"611130929","full_name":"IvanMurzak/Unity-ImageLoader","owner":"IvanMurzak","description":"Asynchronous image loading from remote or local destination. It has two layers of configurable cache system: RAM and Disk.","archived":false,"fork":false,"pushed_at":"2025-03-31T12:05:53.000Z","size":1657,"stargazers_count":148,"open_issues_count":3,"forks_count":20,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-04T01:04:42.945Z","etag":null,"topics":["unity","unity-2d","unity-engine","unity-package","unity-plugin"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IvanMurzak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-08T07:14:41.000Z","updated_at":"2025-04-03T15:21:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"f89f022c-8d83-4a72-a687-1a7ff505a3fb","html_url":"https://github.com/IvanMurzak/Unity-ImageLoader","commit_stats":null,"previous_names":["ivanmurzak/unity-imageloader"],"tags_count":25,"template":false,"template_full_name":"IvanMurzak/Unity-Package-Template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanMurzak%2FUnity-ImageLoader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanMurzak%2FUnity-ImageLoader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanMurzak%2FUnity-ImageLoader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IvanMurzak%2FUnity-ImageLoader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IvanMurzak","download_url":"https://codeload.github.com/IvanMurzak/Unity-ImageLoader/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248643006,"owners_count":21138353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["unity","unity-2d","unity-engine","unity-package","unity-plugin"],"created_at":"2024-10-10T10:13:51.901Z","updated_at":"2025-04-12T22:37:02.316Z","avatar_url":"https://github.com/IvanMurzak.png","language":"C#","readme":"# Unity Image Loader\n\n![npm](https://img.shields.io/npm/v/extensions.unity.imageloader) [![openupm](https://img.shields.io/npm/v/extensions.unity.imageloader?label=openupm\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/extensions.unity.imageloader/) ![License](https://img.shields.io/github/license/IvanMurzak/Unity-ImageLoader) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)\n\n![2019.4.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2019.4.40f1_editor.yml?label=2019.4.40f1-Editor) ![2020.3.40f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2020.3.40f1_editor.yml?label=2020.3.40f1-Editor) ![2021.3.45f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2021.3.45f1_editor.yml?label=2021.3.45f1-Editor) ![2022.3.57f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2022.3.57f1_editor.yml?label=2022.3.57f1-Editor) ![2023.1.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.1.20f1_editor.yml?label=2023.1.20f1-Editor) ![2023.2.20f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/2023.2.20f1_editor.yml?label=2023.2.20f1-Editor) ![6000.0.37f1](https://img.shields.io/github/actions/workflow/status/IvanMurzak/Unity-ImageLoader/6000.0.37f1_editor.yml?label=6000.0.37f1-Editor)\n\nAsync image loader with two caching layers for Unity. It supports loading images from web or local paths and provides memory and disk caching to optimize performance. The package includes features for automatic image setting, cancellation handling, error handling, and lifecycle management.\n\nWait for image get loaded then set:\n\n```csharp\nimage.sprite = await ImageLoader.LoadSprite(imageURL);\n```\n\nDon't wait, use callback to set loaded image later:\n\n```csharp\nImageLoader.LoadSprite(imageURL).Consume(image).Forget();\n```\n\nUse callback to set image and still wait for the completion:\n\n```csharp\nawait ImageLoader.LoadSprite(imageURL).Consume(image);\n```\n\n## Features\n\n- ✔️ Async loading from **Web** or **Local** `ImageLoader.LoadSprite(imageURL);`\n- ✔️ **Memory** and **Disk** caching - tries to load from memory first, then from disk\n- ✔️ Dedicated thread for disk operations\n- ✔️ Supports loading of `Texture2D` and `Sprite`\n- ✔️ Avoids loading same image multiple times simultaneously, a new load task waits for completion of existed task\n- ✔️ Uses `UnityWebRequest` to load data which works smooth across all platforms including `WebGL`\n- ✔️ Cache supported on at `WebGL`. Memory cache works, Disk cache isn't allowed by the platform\n- ✔️ Set into Image `ImageLoader.LoadSprite(imageURL).Consume(image);`\n- ✔️ Set into RawImage `ImageLoader.LoadSprite(imageURL).Consume(rawImage);`\n- ✔️ Set into Material `ImageLoader.LoadSprite(imageURL).Consume(\"_MainTex\", material);`\n- ✔️ Set into SpriteRenderer `ImageLoader.LoadSprite(imageURL).Consume(spriteRenderer);`\n- ✔️ [Set into anything](#cancellation)\n- ✔️ Cancellation `ImageLoader.LoadSprite(imageURL).Cancel();`\n- ✔️ Cancellation callback `ImageLoader.LoadSprite(imageURL).Cancelled(() =\u003e ...);`\n- ✔️ Error callback `ImageLoader.LoadSprite(imageURL).Failed(exception =\u003e ...);`\n- ✔️ Debug level for logging `ImageLoader.settings.debugLevel = DebugLevel.Error;`\n- ✔️ Debug level per each task `ImageLoader.LoadSprite(imageURL).SetLogLevel(DebugLevel.Trace);`\n\n## Content\n\n- [Unity Image Loader](#unity-image-loader)\n  - [Features](#features)\n  - [Content](#content)\n  - [Installation](#installation)\n- [Usage](#usage)\n  - [Events lifecycle](#events-lifecycle)\n  - [Load `Sprite` then set into `Image`](#load-sprite-then-set-into-image)\n  - [Load `Texture2D` then set into `Material`](#load-texture2d-then-set-into-material)\n  - [Load `Sprite` then set into multiple `Image`](#load-sprite-then-set-into-multiple-image)\n  - [Error handling](#error-handling)\n  - [Async `await` and `Forget`](#async-await-and-forget)\n  - [Placeholder](#placeholder)\n  - [Cancellation](#cancellation)\n    - [Cancel by MonoBehaviour events](#cancel-by-monobehaviour-events)\n    - [Explicit cancellation](#explicit-cancellation)\n    - [Cancellation Token](#cancellation-token)\n    - [Cancellation by `using`](#cancellation-by-using)\n    - [Timeout](#timeout)\n  - [Cache](#cache)\n    - [Setup Cache](#setup-cache)\n      - [Change Disk cache folder](#change-disk-cache-folder)\n      - [Override for a specific loading task](#override-for-a-specific-loading-task)\n    - [Manually read / write into cache](#manually-read--write-into-cache)\n    - [Check cache existence](#check-cache-existence)\n    - [Clear cache](#clear-cache)\n  - [Texture Memory Management](#texture-memory-management)\n    - [Manual Memory cache cleaning](#manual-memory-cache-cleaning)\n    - [Automatic Memory cache cleaning](#automatic-memory-cache-cleaning)\n      - [Load Reference](#load-reference)\n      - [Dispose `Reference\u003cT\u003e` on `Component` destroy event](#dispose-referencet-on-component-destroy-event)\n      - [Get references count](#get-references-count)\n- [Other](#other)\n  - [Understanding `IFuture\u003cT\u003e`](#understanding-ifuturet)\n    - [Key Properties of `IFuture\u003cT\u003e`](#key-properties-of-ifuturet)\n    - [Key Methods of `IFuture\u003cT\u003e`](#key-methods-of-ifuturet)\n    - [Example Usage of `IFuture\u003cT\u003e`](#example-usage-of-ifuturet)\n  - [Understanding `Reference\u003cT\u003e`](#understanding-referencet)\n    - [Key Properties of `Reference\u003cT\u003e`](#key-properties-of-referencet)\n    - [Key Methods of `Reference\u003cT\u003e`](#key-methods-of-referencet)\n    - [Example Usage of `Reference\u003cT\u003e`](#example-usage-of-referencet)\n  - [Understanding `Future\u003cReference\u003cT\u003e\u003e`](#understanding-futurereferencet)\n    - [Why It Is Needed](#why-it-is-needed)\n\n---\n\n## Installation\n\n- [Install OpenUPM-CLI](https://github.com/openupm/openupm-cli#installation)\n- Open command line in Unity project folder\n- Run the command\n\n``` CLI\nopenupm add extensions.unity.imageloader\n```\n\n# Usage\n\nIn the main thread somewhere at the start of the project need to call `ImageLoader.Init();` once to initialize static properties in the right thread. It is required to make in the main thread. Then you can use `ImageLoader` from any thread and at any time.\n\n```csharp\nImageLoader.Init(); // just once from the main thread\n```\n\n## Events lifecycle\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLifecycle.cs)\n\n`ImageLoader.LoadSprite` returns `IFuture\u003cSprite\u003e`. This instance provides all range of callbacks and API to modify it. [Understanding `IFuture\u003cT\u003e`](#understanding-ifuturet).\n\n```csharp\nImageLoader.LoadSprite(imageURL) // loading process started\n    // ┌──────────────────────────┬────────────────────────────────────────────────────────────────────────┐\n    // │ Loading lifecycle events │                                                                        │\n    // └──────────────────────────┘                                                                        │\n    .LoadedFromMemoryCache(sprite =\u003e Debug.Log(\"Loaded from memory cache\")) // on loaded from memory cache │\n    .LoadingFromDiskCache (()     =\u003e Debug.Log(\"Loading from disk cache\"))  // on loading from disk cache  │\n    .LoadedFromDiskCache  (sprite =\u003e Debug.Log(\"Loaded from disk cache\"))   // on loaded from disk cache   │\n    .LoadingFromSource    (()     =\u003e Debug.Log(\"Loading from source\"))      // on loading from source      │\n    .LoadedFromSource     (sprite =\u003e Debug.Log(\"Loaded from source\"))       // on loaded from source       │\n    // ────────────────────────────────────────────────────────────────────────────────────────────────────┘\n\n    // ┌──────────────────────────┬───────────────────────────────────────────┐\n    // │ Success lifecycle events │                                           │\n    // └──────────────────────────┘                                           │\n    .Loaded(sprite =\u003e Debug.Log(\"Loaded\")) // on successfully loaded          │\n    //               ┌────────────────────────────────────────────────────────┤\n    //               │ Set/Consume sprite [placeholder, successfully loaded]  │\n    //               └────────────────────────────────────────────────────────┤\n    .Consume(sprite =\u003e Debug.Log(\"Consumed\"))                              // │\n    .Consume(image)                                                        // │\n    // ───────────────────────────────────────────────────────────────────────┘\n\n    // ┌───────────────────────────┬──────────────────────────────────────────┐\n    // │ Negative lifecycle events │                                          │\n    // └───────────────────────────┘                                          │\n    .Canceled(() =\u003e Debug.Log(\"Canceled\"))              // on canceled        │\n    .Failed(exception =\u003e Debug.LogException(exception)) // on failed to load  │\n    // ───────────────────────────────────────────────────────────────────────┘\n\n    // ┌──────────────────────┬──────────────────────────────────────────────────────────────────────────┐\n    // │ The end of lifecycle │                                                                          │\n    // └──────────────────────┘                                                                          │\n    .Completed(isLoaded =\u003e Debug.Log($\"Completed, isLoaded={isLoaded}\")) // on completed                 │\n    //                                                                   // [loaded, failed or canceled] │\n    // ──────────────────────────────────────────────────────────────────────────────────────────────────┘\n\n    .Forget(); // removes the compilation warning, does nothing else\n```\n\n## Load `Sprite` then set into `Image`\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeImage.cs)\n\n```csharp\n// Load a sprite from the web and cache it for faster loading next time\nimage.sprite = await ImageLoader.LoadSprite(imageURL);\n\n// Load a sprite from the web and set it directly to the Image component\nawait ImageLoader.LoadSprite(imageURL).Consume(image);\n```\n\n## Load `Texture2D` then set into `Material`\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadTextureConsumeMaterial.cs)\n\n```csharp\n// Load a Texture2D from the web and cache it for faster loading next time\nmaterial.mainTexture = await ImageLoader.LoadTexture(imageURL);\n\n// Load a Texture2D from the web and set it directly to the Material\nawait ImageLoader.LoadTexture(imageURL).Consume(material);\n```\n\n## Load `Sprite` then set into multiple `Image`\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleLoadSpriteConsumeIntoMultipleImages.cs)\n\n```csharp\nImageLoader.LoadSprite(imageURL).Consume(image1, image2).Forget();\n```\n\n## Error handling\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleErrorHandle.cs)\n\n```csharp\nImageLoader.LoadSprite(imageURL) // Attempt to load a sprite\n    .Consume(image) // If successful, set the sprite to the Image component\n    .Failed(exception =\u003e Debug.LogException(exception)) // If an error occurs, log the exception\n    .Forget(); // Forget the task to avoid compilation warning\n\nImageLoader.LoadSprite(imageURL) // Attempt to load a sprite\n    .Consume(image) // If successful, set the sprite to the Image component\n    .Then(sprite =\u003e image.gameObject.SetActive(true)) // If successful, activate the GameObject\n    .Failed(exception =\u003e image.gameObject.SetActive(false)) // If an error occurs, deactivate the GameObject\n    .Forget(); // Forget the task to avoid compilation warning\n```\n\n## Async `await` and `Forget`\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleAwaitAndForget.cs)\n\n```csharp\n// Load image and wait\nawait ImageLoader.LoadSprite(imageURL);\n\n// Load image, set image and wait\nawait ImageLoader.LoadSprite(imageURL).Consume(image);\n\n// Skip waiting for completion.\n// To do that we can simply remove 'await' from the start.\n// To avoid compilation warning need to add '.Forget()'.\nImageLoader.LoadSprite(imageURL).Consume(image).Forget();\n```\n\n## Placeholder\n\nWhile the target image is loading it would be a good idea to set placeholder image. Also, it works well for setting image if loading fails.\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SamplePlaceholder.cs)\n\n```csharp\nImageLoader.LoadSprite(imageURL)\n    // set placeholder in all conditions\n    .SetPlaceholder(placeholderAny)\n\n    // set placeholder in a specific conditions\n    .SetPlaceholder(placeholderLoadingFromSource, PlaceholderTrigger.LoadingFromSource)\n    .SetPlaceholder(placeholderFailedToLoad, PlaceholderTrigger.FailedToLoad)\n\n    // set consumer\n    .Consume(image)\n    .Forget();\n```\n\n## Cancellation\n\nCancellation is helpful if target image consumer doesn't exist anymore. For example the `Image` was destroyed because another level had been loaded. The is not much sense to continue to load the image. It would safe some network traffic, CPU resources, and RAM. `IFuture\u003cT\u003e` provides wide range of options to cancel the ongoing loading process.\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleCancellation.cs)\n\n### Cancel by MonoBehaviour events\n\n```csharp\nImageLoader.LoadSprite(imageURL)\n    .Consume(image)\n    .CancelOnEnable(this)   // cancel on OnEnable event of current MonoBehaviour\n    .CancelOnDisable(this)  // cancel on OnDisable event of current MonoBehaviour\n    .CancelOnDestroy(this); // cancel on OnDestroy event of current MonoBehaviour\n```\n\n### Explicit cancellation\n\n```csharp\nvar future = ImageLoader.LoadSprite(imageURL).Consume(image);\nfuture.Cancel();\n```\n\n### Cancellation Token\n\n```csharp\nvar cancellationTokenSource = new CancellationTokenSource();\n\n// loading with attached cancellation token\nImageLoader.LoadSprite(imageURL, cancellationToken: cancellationTokenSource.Token)\n    .Consume(image)\n    .Forget();\n\ncancellationTokenSource.Cancel(); // canceling\n```\n\n```csharp\nvar cancellationTokenSource = new CancellationTokenSource();\n\nImageLoader.LoadSprite(imageURL)\n    .Consume(image)\n    .Register(cancellationTokenSource.Token) // registering cancellation token\n    .Forget();\n\ncancellationTokenSource.Cancel(); // canceling\n```\n\n### Cancellation by `using`\n\n```csharp\nusing (var future = ImageLoader.LoadSprite(imageURL).Consume(image))\n{\n    // future would be canceled and disposed outside of the brackets\n}\n```\n\n```csharp\nImageLoader.LoadSprite(imageURL) // load sprite\n    .Consume(image) // if success set sprite into image\n    .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject\n    .Forget();\n\nImageLoader.LoadSprite(imageURL) // load sprite\n    .Consume(image) // if success set sprite into image\n    .Failed(exception =\u003e Debug.LogException(exception)) // if fail print exception\n    .CancelOnDestroy(this) // cancel OnDestroy event of current gameObject\n    .Forget();\n\nImageLoader.LoadSprite(imageURL) // load sprite\n    .Consume(image) // if success set sprite into image\n    .Then(sprite =\u003e image.gameObject.SetActive(true)) // if success activate gameObject\n    .Failed(exception =\u003e image.gameObject.SetActive(false)) // if fail deactivate gameObject\n    .Canceled(() =\u003e Debug.Log(\"ImageLoading canceled\")) // if cancelled\n    .CancelOnDisable(this) // cancel OnDisable event of current gameObject\n    .Forget();\n```\n\n### Timeout\n\nTimeout triggers `IFuture\u003cT\u003e` cancellation.\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleTimeout.cs)\n\nSet global timeout in the settings:\n\n```csharp\nImageLoader.settings.timeout = TimeSpan.FromSeconds(30);\n```\n\nSet timeout for a specific loading request (`IFuture\u003cT\u003e`):\n\n```csharp\nImageLoader.LoadSprite(imageURL) // load sprite\n    .Consume(image) // if success set sprite into image\n    .Timeout(TimeSpan.FromSeconds(10)) // set timeout duration 10 seconds\n    .Forget();\n```\n\n## Cache\n\nCache system based on the two layers. The first layer is **Memory cache**, second is **Disk cache**. Each layer could be enabled or disabled. Could be used without caching at all. By default both layers are enabled. `WebGL` doesn't support Disk cache, because it doesn't have access to disk.\n\n### Setup Cache\n\n- `ImageLoader.settings.useMemoryCache = true;` default value is `true`\n- `ImageLoader.settings.useDiskCache = true;` default value is `true`\n\n#### Change Disk cache folder\n\nBy default it uses `Application.persistentDataPath + \"/ImageLoader\"`\n\n```csharp\nImageLoader.settings.diskSaveLocation = Application.persistentDataPath + \"/myCustomFolder\";\n```\n\n#### Override for a specific loading task\n\nIt overrides global `ImageLoader.settings`\n\n```csharp\nImageLoader.LoadSprite(url)\n    .SetUseDiskCache(false)\n    .SetUseMemoryCache(true);\n```\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleCache.cs)\n\n### Manually read / write into cache\n\n```csharp\n// Override Memory cache for specific image\nImageLoader.SaveToMemoryCache(url, sprite);\n\n// Take from Memory cache for specific image if exists\nImageLoader.LoadSpriteFromMemoryCache(url);\n```\n\n### Check cache existence\n\n```csharp\n// Check if any cache contains specific image\nImageLoader.CacheContains(url);\n\n// Check if Memory cache contains specific image\nImageLoader.MemoryCacheContains(url);\n\n// Check if Disk cache contains specific image\nImageLoader.DiskCacheContains(url);\n```\n\n### Clear cache\n\n```csharp\n// Clear memory Memory and Disk cache for all images\nImageLoader.ClearCacheAll();\n\n// Clear only Memory and Disk cache for specific image\nImageLoader.ClearCache(url);\n\n// Clear only Memory cache for all images\nImageLoader.ClearMemoryCacheAll();\n\n// Clear only Memory cache for specific image\nImageLoader.ClearMemoryCache(url);\n\n// Clear only Disk cache for all images\nImageLoader.ClearDiskCacheAll();\n\n// Clear only Disk cache for specific image\nImageLoader.ClearDiskCache(url);\n```\n\nMemory cache could be cleared automatically if to use `Reference\u003cT\u003e` and the heavy `Texture2D` memory would be released as well. Read more at [Texture Memory Management](#texture-memory-management).\n\n## Texture Memory Management\n\nTexture2D objects consume a lot of memory. Ignoring it may impact performance or even trigger `OutOfMemory` crash by operation system. To avoid it, let's dig deeper into tools the package provides. We worry less about Disk cache, because it doesn't impact game performance directly. Let's focus on the Memory cache.\n\n### Manual Memory cache cleaning\n\nIt is simple, just executing this line of code would release memory of a single Texture2D in the case if no other `Reference` pointing on it exists. Before doing that please make sure that no Unity component is using the texture.\n\n```csharp\nImageLoader.ClearMemoryCache(url);\n```\n\nUnder the hood it calls `UnityEngine.Object.DestroyImmediate(texture)`.\n\n\u003e :warning: Releasing `Texture2D` from memory while any Unity's component uses it may trigger native app crash or even Unity Editor crash\n\n### Automatic Memory cache cleaning\n\nImageLoader can manager memory releasing of loaded textures. To use it need to call `ImageLoader.LoadSpriteRef` instead of `ImageLoader.LoadSprite`. It returns `Reference\u003cSprite\u003e` object which contains `Sprite` and `Url`. When `Reference\u003cSprite\u003e` object is not needed anymore, call `reference.Dispose()` method to release memory, or just don't save the reference on it. It is `IDisposable` and it will be disposed by Garbage Collector. Each new instance of `Reference\u003cSprite\u003e` increments reference counter of the texture. When the last reference is disposed, the texture memory releases. Also, if any reference is alive, calling `ImageLoader.ClearMemoryCache` or `ImageLoader.ClearCache` would have zero effect for only referenced textures. It prints warning messages about it.\n\n```csharp\n// Load sprite image and get reference to it\nvar reference = await ImageLoader.LoadSpriteRef(imageURL);\n\n// Take from Memory cache reference for specific image if exists\nvar reference = ImageLoader.LoadSpriteRefFromMemoryCache(url);\n\n// Dispose `reference` when you don't need the texture anymore\nreference.Dispose();\n\n// You may also nullify the reference to let Garbage Collector at some point to Dispose it for you\nreference = null;\n```\n\n\u003e :warning: Releasing `Texture2D` from memory while any Unity's component uses it may trigger native app crash or even Unity Editor crash. Please pay enough attention to manage `Reference\u003cT\u003e` instances in a proper way. Or do not use them.\n\n#### Load Reference\n\n\u003e [Full sample source code](https://github.com/IvanMurzak/Unity-ImageLoader/blob/master/Assets/_PackageRoot/Samples/SampleReferences.cs)\n\n`Future\u003cReference\u003cT\u003e\u003e.Consume` has a unique feature to attach the reference to the target consumer if consumer is `UnityEngine.Component`. The reference would be disposed as only the consumer gets destroyed.\n\n```csharp\nImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference\n    .Consume(image) // if success set sprite into image, also creates binding to `image`\n    .Forget();\n```\n\n#### Dispose `Reference\u003cT\u003e` on `Component` destroy event\n\nIt automatically dispose the reference as only `this.gameObject` gets `OnDestroy` callback.\n\n```csharp\nImageLoader.LoadSpriteRef(imageURL) // load sprite using Reference\n    .Then(reference =\u003e reference.DisposeOnDestroy(this))\n    .Then(reference =\u003e\n    {\n        var sprite = reference.Value;\n        // use sprite\n    })\n    .Forget();\n```\n\n#### Get references count\n\n```csharp\nvar count = ImageLoader.GetReferenceCount(imageURL); // get count of references\n```\n\n---\n\n# Other\n\n## Understanding `IFuture\u003cT\u003e`\n\nThe `IFuture\u003cT\u003e` interface represents an asynchronous operation that will eventually produce a result of type `T`. It provides a range of methods and properties to handle the lifecycle of the asynchronous operation, including loading, success, failure, and cancellation events.\n\n### Key Properties of `IFuture\u003cT\u003e`\n\n- **`Id`**: Unique identifier for the future.\n- **`Url`**: URL associated with the future.\n- **`IsCancelled`**: Indicates if the operation has been cancelled.\n- **`IsLoaded`**: Indicates if the operation has successfully loaded the result.\n- **`IsCompleted`**: Indicates if the operation has completed (either successfully or with an error).\n- **`IsInProgress`**: Indicates if the operation is currently in progress.\n- **`Status`**: Current status of the future.\n- **`CancellationToken`**: Token used to cancel the operation.\n- **`Value`**: The result of the operation.\n- **`LogLevel`**: The logging level for the operation.\n\n### Key Methods of `IFuture\u003cT\u003e`\n\n- **``Then(Action\u003cT\u003e onCompleted)``**: Registers a callback to be executed when the operation successfully completes and produces a result.\n- **`Failed(Action\u003cException\u003e action)`**: Registers a callback to be executed if the operation fails with an exception.\n- **`Completed(Action\u003cbool\u003e action)`**: Registers a callback to be executed when the operation completes, regardless of success or failure. The boolean parameter indicates whether the operation was successful.\n- **`Canceled(Action action)`**: Registers a callback to be executed if the operation is canceled.\n- **`SetUseDiskCache(bool value = true)`**: Configures whether the operation should use disk caching.\n- **`SetUseMemoryCache(bool value = true)`**: Configures whether the operation should use memory caching.\n- **`SetLogLevel(DebugLevel value)`**: Sets the logging level for the operation.\n- **`Cancel()`**: Cancels the operation if it is still in progress.\n- **`Forget()`**: Ignores the result of the operation, useful for avoiding compilation warnings about unawaited tasks.\n- **`AsUniTask()`**: Converts the `IFuture\u003cT\u003e` instance to a `UniTask\u003cT\u003e`.\n- **`AsTask()`**: Converts the `IFuture\u003cT\u003e` instance to a `Task\u003cT\u003e`.\n- **`AsReference(DebugLevel logLevel = DebugLevel.Trace)`**: Converts the `IFuture\u003cT\u003e` instance to a `Future\u003cReference\u003cT\u003e\u003e` instance.\n- **`GetAwaiter()`**: Returns an awaiter for the `IFuture\u003cT\u003e` instance, allowing it to be awaited using the `await` keyword.\n- **`PassEvents(IFutureInternal\u003cT\u003e to, bool passCancelled = true)`**: Passes events to another future.\n- **`PassEvents\u003cT2\u003e(IFutureInternal\u003cT2\u003e to, Func\u003cT, T2\u003e convert, bool passCancelled = true)`**: Passes events to another future with conversion.\n- **`Register(CancellationToken cancellationToken)`**: Registers a new cancellation token to cancel the future with it.\n- **`Timeout(TimeSpan duration)`**: Sets a timeout duration for the future. If the duration is reached, it fails the future with a related exception.\n\n### Example Usage of `IFuture\u003cT\u003e`\n\n```csharp\nImageLoader.LoadSprite(imageURL) // Start loading the sprite\n    .Then(sprite =\u003e Debug.Log(\"Loaded\")) // On successful load\n    .Failed(exception =\u003e Debug.LogException(exception)) // On failure\n    .Completed(isLoaded =\u003e Debug.Log($\"Completed, isLoaded={isLoaded}\")) // On completion\n    .Canceled(() =\u003e Debug.Log(\"Canceled\")) // On cancellation\n    .Forget(); // Avoid compilation warnings\n```\n\n## Understanding `Reference\u003cT\u003e`\n\nThe `Reference\u003cT\u003e` class is used to manage the lifecycle of loaded resources, such as `Texture2D` or `Sprite`, in a memory-efficient manner. It helps to automatically release memory when the resource is no longer needed, preventing memory leaks and optimizing performance.\n\n### Key Properties of `Reference\u003cT\u003e`\n\n- **`Value`**: The actual resource (e.g., `Sprite` or `Texture2D`) that is being referenced.\n- **`Url`**: The URL associated with the resource.\n- **`IsDisposed`**: Indicates whether the reference has been disposed.\n\n### Key Methods of `Reference\u003cT\u003e`\n\n- **`Dispose()`**: Disposes the reference, releasing the associated resource from memory. This should be called when the resource is no longer needed.\n- **`DisposeOnDestroy(Component component)`**: Automatically disposes the reference when the specified `Component` is destroyed. This is useful for ensuring that resources are released when the associated GameObject is destroyed.\n- **`DisposeOnDisable(Component component)`**: Automatically disposes the reference when the specified `Component` is disabled.\n- **`DisposeOnEnable(Component component)`**: Automatically disposes the reference when the specified `Component` is enabled.\n\n### Example Usage of `Reference\u003cT\u003e`\n\n```csharp\n// Load a sprite using Reference\nvar reference = await ImageLoader.LoadSpriteRef(imageURL);\n\n// Use the sprite\nvar sprite = reference.Value;\n\n// Dispose the reference when the sprite is no longer needed\nreference.Dispose();\n```\n\n```csharp\n// Alternatively, automatically dispose the reference when the GameObject is destroyed\nImageLoader.LoadSpriteRef(imageURL)\n    .Then(reference =\u003e reference.DisposeOnDestroy(this))\n    .Then(reference =\u003e\n    {\n        var sprite = reference.Value;\n        // use sprite\n    })\n    .Forget();\n```\n\n## Understanding `Future\u003cReference\u003cT\u003e\u003e`\n\nThe `Future\u003cReference\u003cT\u003e\u003e` class combines the functionality of `IFuture\u003cT\u003e` and `Reference\u003cT\u003e`, providing a powerful tool for managing the lifecycle of asynchronous operations that produce resources such as `Texture2D` or `Sprite`. This combination allows you to handle the loading process and the resource management in a memory-efficient manner.\n\n### Why It Is Needed\n\nThe `Future\u003cReference\u003cT\u003e\u003e` class is needed to ensure that resources are loaded asynchronously and managed efficiently. By using this class, you can:\n\n1. **Load Resources Asynchronously**: Start loading resources such as `Texture2D` or `Sprite` without blocking the main thread.\n2. **Manage Resource Lifecycle**: Automatically release resources when they are no longer needed, preventing memory leaks and optimizing performance.\n3. **Handle Loading Events**: Register callbacks for various events such as success, failure, and cancellation during the loading process.\n4. **Bind Resources to Components**: Automatically dispose of resources when the associated `UnityEngine.Component` is destroyed, ensuring that resources are released when the GameObject is destroyed.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanmurzak%2Funity-imageloader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivanmurzak%2Funity-imageloader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanmurzak%2Funity-imageloader/lists"}