/// <summary> /// Sets an image or gif/apng from a resource path /// </summary> /// <param name="image">Image component to set the image to</param> /// <param name="location">Resource path, file path, or url of image. Can prefix with # to find and use a base game sprite. May need to prefix resource paths with 'AssemblyName:'</param> public static void SetImage(this Image image, string location) { AnimationStateUpdater oldStateUpdater = image.GetComponent <AnimationStateUpdater>(); if (oldStateUpdater != null) { MonoBehaviour.DestroyImmediate(oldStateUpdater); } bool isURL = Uri.TryCreate(location, UriKind.Absolute, out Uri uri); if (location.StartsWith("#")) { string imgName = location.Substring(1); try { image.sprite = Resources.FindObjectsOfTypeAll <Sprite>().First(x => x.name == imgName); } catch { Logger.log.Error($"Could not find Texture with image name {imgName}"); } } else if (IsAnimated(location) || (isURL && IsAnimated(uri.LocalPath))) { AnimationStateUpdater stateUpdater = image.gameObject.AddComponent <AnimationStateUpdater>(); stateUpdater.image = image; stateUpdater.controllerData = AnimationController.instance.loadingAnimation; if (AnimationController.instance.RegisteredAnimations.TryGetValue(location, out AnimationControllerData animControllerData)) { stateUpdater.controllerData = animControllerData; } else { Utilities.GetData(location, (byte[] data) => { AnimationLoader.Process((location.EndsWith(".gif") || (isURL && uri.LocalPath.EndsWith(".gif"))) ? AnimationType.GIF : AnimationType.APNG, data, (Texture2D tex, Rect[] uvs, float[] delays, int width, int height) => { AnimationControllerData controllerData = AnimationController.instance.Register(location, tex, uvs, delays); stateUpdater.controllerData = controllerData; }); }); } } else { AnimationStateUpdater stateUpdater = image.gameObject.AddComponent <AnimationStateUpdater>(); stateUpdater.image = image; stateUpdater.controllerData = AnimationController.instance.loadingAnimation; Utilities.GetData(location, (byte[] data) => { if (stateUpdater != null) { GameObject.DestroyImmediate(stateUpdater); } image.sprite = Utilities.LoadSpriteRaw(data); image.sprite.texture.wrapMode = TextureWrapMode.Clamp; }); } }
//////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// <summary> /// On single image cached /// </summary> /// <param name="p_ID"></param> /// <param name="p_Bytes">Result bytes</param> /// <param name="p_IsAnimated">Is and animation image</param> /// <param name="p_Finally">A callback that occurs after the resource is retrieved. This will always occur even if the resource is already cached.</param> /// <param name="p_ForcedHeight">Forced height</param> /// <returns></returns> private IEnumerator OnSingleImageCached(string p_ID, byte[] p_Bytes, bool p_IsAnimated, Action <EnhancedImageInfo> p_Finally = null, int p_ForcedHeight = -1) { int l_SpriteWidth = 0; int l_SpriteHeight = 0; Sprite l_Sprite = null; AnimationControllerData l_AnimControllerData = null; if (p_IsAnimated) { AnimationLoader.Process(AnimationType.GIF, p_Bytes, (p_Texture, p_Atlas, p_Delays, p_Width, p_Height) => { l_AnimControllerData = AnimationController.instance.Register(p_ID, p_Texture, p_Atlas, p_Delays); l_Sprite = l_AnimControllerData.sprite; l_SpriteWidth = p_Width; l_SpriteHeight = p_Height; }); yield return(new WaitUntil(() => l_AnimControllerData != null)); } else { try { l_Sprite = BeatSaberPlus.Utils.UnityTexture.LoadSpriteRaw(p_Bytes); l_SpriteWidth = l_Sprite.texture.width; l_SpriteHeight = l_Sprite.texture.height; } catch (Exception p_Exception) { Logger.Instance.Error("Error in OnSingleImageCached"); Logger.Instance.Error(p_Exception); l_Sprite = null; } } EnhancedImageInfo l_Result = null; if (l_Sprite != null) { if (p_ForcedHeight != -1) { ComputeImageSizeForHeight(ref l_SpriteWidth, ref l_SpriteHeight, p_ForcedHeight); } l_Result = new EnhancedImageInfo() { ImageID = p_ID, Sprite = l_Sprite, Width = l_SpriteWidth, Height = l_SpriteHeight, AnimControllerData = l_AnimControllerData }; m_CachedImageInfo[p_ID] = l_Result; } p_Finally?.Invoke(l_Result); }
public IEnumerator OnSingleImageCached(byte[] bytes, string id, bool isAnimated, Action <EnhancedImageInfo> Finally = null, int forcedHeight = -1) { if (bytes.Length == 0) { Finally(null); yield break; } Sprite sprite = null; int spriteWidth = 0, spriteHeight = 0; AnimationControllerData animControllerData = null; if (isAnimated) { AnimationLoader.Process(AnimationType.GIF, bytes, (tex, atlas, delays, width, height) => { animControllerData = AnimationController.instance.Register(id, tex, atlas, delays); sprite = animControllerData.sprite; spriteWidth = width; spriteHeight = height; }); yield return(new WaitUntil(() => animControllerData != null)); } else { try { sprite = GraphicUtils.LoadSpriteRaw(bytes); spriteWidth = sprite.texture.width; spriteHeight = sprite.texture.height; } catch (Exception ex) { Logger.log.Error(ex); sprite = null; } } EnhancedImageInfo ret = null; if (sprite != null) { if (forcedHeight != -1) { SetImageHeight(ref spriteWidth, ref spriteHeight, forcedHeight); } ret = new EnhancedImageInfo() { ImageId = id, Sprite = sprite, Width = spriteWidth, Height = spriteHeight, AnimControllerData = animControllerData }; _cachedImageInfo[id] = ret; } Finally?.Invoke(ret); }
public IEnumerator OnSingleImageCached(byte[] bytes, string id, ESCAnimationType animatedType, Action <EnhancedImageInfo> Finally = null, int forcedHeight = -1) { if (bytes.Length == 0) { Finally(null); yield break; } Sprite sprite = null; int spriteWidth = 0, spriteHeight = 0; AnimationControllerData animControllerData = null; switch (animatedType) { case ESCAnimationType.GIF: AnimationLoader.Process(AnimationType.GIF, bytes, (tex, atlas, delays, width, height) => { animControllerData = AnimationController.instance.Register(id, tex, atlas, delays); sprite = animControllerData.sprite; spriteWidth = width; spriteHeight = height; }); yield return(new WaitUntil(() => animControllerData != null)); break; case ESCAnimationType.APNG: AnimationLoader.Process(AnimationType.APNG, bytes, (tex, atlas, delays, width, height) => { animControllerData = AnimationController.instance.Register(id, tex, atlas, delays); sprite = animControllerData.sprite; spriteWidth = width; spriteHeight = height; }); yield return(new WaitUntil(() => animControllerData != null)); break; case ESCAnimationType.MAYBE_GIF: if (6 <= bytes.Length && (this.ContainBytePattern(bytes, s_animattedGIF89aPattern) || this.ContainBytePattern(bytes, s_animattedGIF87aPattern))) { AnimationLoader.Process(AnimationType.GIF, bytes, (tex, atlas, delays, width, height) => { animControllerData = AnimationController.instance.Register(id, tex, atlas, delays); sprite = animControllerData.sprite; spriteWidth = width; spriteHeight = height; }); yield return(new WaitUntil(() => animControllerData != null)); } else { try { sprite = GraphicUtils.LoadSpriteRaw(bytes); spriteWidth = sprite.texture.width; spriteHeight = sprite.texture.height; } catch (Exception ex) { Logger.Error(ex); sprite = null; } } break; case ESCAnimationType.WEBP: case ESCAnimationType.NONE: default: try { sprite = GraphicUtils.LoadSpriteRaw(bytes); spriteWidth = sprite.texture.width; spriteHeight = sprite.texture.height; } catch (Exception ex) { Logger.Error(ex); sprite = null; } break; } var ret = this._imageInfoContaner.Spawn(); if (sprite != null) { if (forcedHeight != -1) { this.SetImageHeight(ref spriteWidth, ref spriteHeight, forcedHeight); } ret.ImageId = id; ret.Sprite = sprite; ret.Width = spriteWidth; ret.Height = spriteHeight; ret.AnimControllerData = animControllerData; this.CachedImageInfo.TryAdd(id, ret); } else { this._imageInfoContaner.Despawn(ret); } Finally?.Invoke(ret); }
/// <summary> /// Sets an image or gif/apng from a resource path /// </summary> /// <param name="image">Image component to set the image to</param> /// <param name="location">Resource path, file path, or url of image. Can prefix with # to find and use a base game sprite. May need to prefix resource paths with 'AssemblyName:'</param> /// <param name="loadingAnimation">Whether a loading animation is shown as a placeholder until the image is loaded</param> /// <param name="scaleOptions">If the image should be downscaled and what it should be downscaled to</param> /// <param name="callback">Method to call once SetImage has finished</param> public static void SetImage(this Image image, string location, bool loadingAnimation, ScaleOptions scaleOptions, Action callback) { AnimationStateUpdater oldStateUpdater = image.GetComponent <AnimationStateUpdater>(); if (oldStateUpdater != null) { MonoBehaviour.DestroyImmediate(oldStateUpdater); } if (location.Length > 1 && location[0] == '#') { string imgName = location.Substring(1); image.sprite = Utilities.FindSpriteCached(imgName); if (image.sprite == null) { Logger.log.Error($"Could not find Sprite with image name {imgName}"); } return; } bool isURL = Uri.TryCreate(location, UriKind.Absolute, out Uri uri); if (IsAnimated(location) || isURL && IsAnimated(uri.LocalPath)) { AnimationStateUpdater stateUpdater = image.gameObject.AddComponent <AnimationStateUpdater>(); stateUpdater.image = image; if (loadingAnimation) { stateUpdater.controllerData = AnimationController.instance.loadingAnimation; } if (AnimationController.instance.RegisteredAnimations.TryGetValue(location, out AnimationControllerData animControllerData)) { stateUpdater.controllerData = animControllerData; } else { Utilities.GetData(location, (byte[] data) => { AnimationLoader.Process( (location.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) || (isURL && uri.LocalPath.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))) ? AnimationType.GIF : AnimationType.APNG, data, (Texture2D tex, Rect[] uvs, float[] delays, int width, int height) => { AnimationControllerData controllerData = AnimationController.instance.Register(location, tex, uvs, delays); stateUpdater.controllerData = controllerData; callback?.Invoke(); }); }); return; } } else { AnimationStateUpdater stateUpdater = image.gameObject.AddComponent <AnimationStateUpdater>(); stateUpdater.image = image; if (loadingAnimation) { stateUpdater.controllerData = AnimationController.instance.loadingAnimation; } Utilities.GetData(location, async(byte[] data) => { if (stateUpdater != null) { GameObject.DestroyImmediate(stateUpdater); } if (scaleOptions.ShouldScale) { var imageBytes = await Task.Run(() => DownScaleImage(data, scaleOptions)).ConfigureAwait(false); _ = UnityMainThreadTaskScheduler.Factory.StartNew(() => { image.sprite = Utilities.LoadSpriteRaw(imageBytes); image.sprite.texture.wrapMode = TextureWrapMode.Clamp; }); } else { image.sprite = Utilities.LoadSpriteRaw(data); image.sprite.texture.wrapMode = TextureWrapMode.Clamp; } callback?.Invoke(); }); return; } callback?.Invoke(); }