private static async Task <ImageSource> GetLottieFrame(string path, int frame, int width, int height) { var dpi = WindowContext.Current.RasterizationScale; width = (int)(width * dpi); height = (int)(height * dpi); var cache = $"{path}.{width}x{height}.png"; if (System.IO.File.Exists(cache)) { return(new BitmapImage(UriEx.ToLocal(cache))); } await Task.Run(() => { var frameSize = new Windows.Graphics.SizeInt32 { Width = width, Height = height }; var animation = LottieAnimation.LoadFromFile(path, frameSize, false, null); if (animation != null) { animation.RenderSync(cache, frame); animation.Dispose(); } }); return(new BitmapImage(UriEx.ToLocal(cache))); }
public static ImageSource GetLottieFrame(string path, int frame, int width, int height, bool webp = true) { // Frame size affects disk cache, so we always use 256. var frameSize = new Windows.Graphics.SizeInt32 { Width = 256, Height = 256 }; var animation = LottieAnimation.LoadFromFile(path, frameSize, false, null); if (animation == null) { if (webp) { return(GetWebPFrame(path, width)); } return(null); } var bitmap = new WriteableBitmap(width, height); animation.RenderSync(bitmap, frame); animation.Dispose(); return(bitmap); }
public static ImageSource GetLottieFrame(string path, int frame, int width, int height, bool webp = true) { var animation = LottieAnimation.LoadFromFile(path, false, null); if (animation == null) { if (webp) { return(GetWebPFrame(path)); } return(null); } var bitmap = new WriteableBitmap(width, height); animation.RenderSync(bitmap, frame); animation.Dispose(); return(bitmap); }
private void OnSourceChanged(string newValue, string oldValue) { var canvas = _canvas; if (canvas == null) { return; } if (newValue == null) { //canvas.Paused = true; //canvas.ResetElapsedTime(); Subscribe(false); Dispose(); return; } if (string.Equals(newValue, oldValue, StringComparison.OrdinalIgnoreCase) || string.Equals(newValue, _source, StringComparison.OrdinalIgnoreCase)) { return; } var animation = LottieAnimation.LoadFromFile(newValue, _isCachingEnabled, ColorReplacements); if (animation == null) { // The app can't access the file specified return; } _source = newValue; _animation = animation; _animationShouldCache = animation.ShouldCache; _animationFrameRate = animation.FrameRate; _animationTotalFrame = animation.TotalFrame; _index = _isCachingEnabled ? 0 : _animationTotalFrame - 1; //canvas.Paused = true; //canvas.ResetElapsedTime(); //canvas.TargetElapsedTime = update > TimeSpan.Zero ? update : TimeSpan.MaxValue; if (AutoPlay || _shouldPlay) { _shouldPlay = false; Subscribe(true); //canvas.Paused = false; } else { Subscribe(false); // Invalidate to render the first frame Invalidate(); _canvas.Invalidate(); } }
private async void OnSourceChanged(string newValue, string oldValue) { var canvas = _canvas; if (canvas == null) { return; } if (newValue == null) { _source = null; Subscribe(false); return; } if (string.Equals(newValue, oldValue, StringComparison.OrdinalIgnoreCase) || string.Equals(newValue, _source, StringComparison.OrdinalIgnoreCase)) { return; } _source = newValue; var shouldPlay = _shouldPlay; var animation = await Task.Run(() => LottieAnimation.LoadFromFile(newValue, _isCachingEnabled, ColorReplacements)); if (animation == null || !string.Equals(newValue, _source, StringComparison.OrdinalIgnoreCase)) { // The app can't access the file specified return; } if (_shouldPlay) { shouldPlay = true; } _animation = animation; _hideThumbnail = true; _animationFrameRate = animation.FrameRate; _animationTotalFrame = animation.TotalFrame; if (_backward) { _index = _animationTotalFrame - 1; } else { _index = 0; //_isCachingEnabled ? 0 : _animationTotalFrame - 1; } //canvas.Paused = true; //canvas.ResetElapsedTime(); //canvas.TargetElapsedTime = update > TimeSpan.Zero ? update : TimeSpan.MaxValue; if (AutoPlay || _shouldPlay) { _shouldPlay = false; Subscribe(true); //canvas.Paused = false; } else if (!_unloaded) { Subscribe(false); // Invalidate to render the first frame Invalidate(); _canvas.Invalidate(); } }
public async void SetValue(DiceStickers state, int newValue) { var canvas = _canvas; if (canvas == null) { _previous = newValue; _previousState = state; return; } if (state == null) { //canvas.Paused = true; //canvas.ResetElapsedTime(); Subscribe(false); Dispose(); return; } if (newValue == _value) { return; } if (newValue != _value && /*newValue != _enqueued &&*/ _value == 0) { if (_subscribed) { _shouldPlay = true; _enqueued = newValue; _enqueuedState = state; return; } } var force = _enqueued == newValue; _value = newValue; _valueState = state; _previous = newValue; _previousState = state; _enqueued = 0; _enqueuedState = null; var initial = newValue == 0; var shouldPlay = _shouldPlay; var animations = new LottieAnimation[_parts]; await Task.Run(() => { if (state is DiceStickersSlotMachine slotMachine) { animations[0] = _backAnimation ??= LottieAnimation.LoadFromFile(slotMachine.Background.StickerValue.Local.Path, false, null); animations[1] = LottieAnimation.LoadFromData(MergeReels(slotMachine), $"{newValue}", false, null); animations[2] = _frontAnimation ??= LottieAnimation.LoadFromFile(slotMachine.Lever.StickerValue.Local.Path, false, null); } else if (state is DiceStickersRegular regular) { animations[1] = LottieAnimation.LoadFromFile(regular.Sticker.StickerValue.Local.Path, false, null); } }); if (_shouldPlay) { shouldPlay = true; } _animations = animations; _isLoopingEnabled[1] = initial; _animationFrameRate = animations.Max(x => x?.FrameRate ?? 0); _animationTotalFrame = animations.Max(x => x?.TotalFrame ?? 0); _startIndex[0] = _animationTotalFrame; _index[0] = 1; _index[1] = IsContentUnread || initial ? 0 : animations[1].TotalFrame - 1; _index[2] = initial ? 0 : _index[2]; //canvas.Paused = true; //canvas.ResetElapsedTime(); //canvas.TargetElapsedTime = update > TimeSpan.Zero ? update : TimeSpan.MaxValue; if (AutoPlay || shouldPlay || force) { _shouldPlay = false; Subscribe(true); //canvas.Paused = false; } else { Subscribe(false); // Invalidate to render the first frame Invalidate(); _canvas?.Invalidate(); } }
private async Task ChatPhotoAsync(UpdateFileGenerationStart update, string[] args) { try { var conversion = JsonConvert.DeserializeObject <ChatPhotoConversion>(args[2]); var sticker = await _protoService.SendAsync(new GetFile(conversion.StickerFileId)) as Telegram.Td.Api.File; if (sticker == null || !sticker.Local.IsFileExisting()) { _protoService.Send(new FinishFileGeneration(update.GenerationId, new Error(500, "FILE_GENERATE_LOCATION_INVALID No sticker found"))); return; } Background background = null; var backgroundLink = await _protoService.SendAsync(new GetInternalLinkType(conversion.BackgroundUrl ?? string.Empty)) as InternalLinkTypeBackground; if (backgroundLink != null) { background = await _protoService.SendAsync(new SearchBackground(backgroundLink.BackgroundName)) as Background; } else { var freeform = new[] { 0xDBDDBB, 0x6BA587, 0xD5D88D, 0x88B884 }; background = new Background(0, true, false, string.Empty, new Document(string.Empty, "application/x-tgwallpattern", null, null, TdExtensions.GetLocalFile("Assets\\Background.tgv", "Background")), new BackgroundTypePattern(new BackgroundFillFreeformGradient(freeform), 50, false, false)); } if (background == null || (background.Document != null && !background.Document.DocumentValue.Local.IsFileExisting())) { _protoService.Send(new FinishFileGeneration(update.GenerationId, new Error(500, "FILE_GENERATE_LOCATION_INVALID No background found"))); return; } var device = CanvasDevice.GetSharedDevice(); var bitmaps = new List <CanvasBitmap>(); var sfondo = new CanvasRenderTarget(device, 640, 640, 96, DirectXPixelFormat.B8G8R8A8UIntNormalized, CanvasAlphaMode.Premultiplied); using (var session = sfondo.CreateDrawingSession()) { if (background.Type is BackgroundTypePattern pattern) { if (pattern.Fill is BackgroundFillFreeformGradient freeform) { var colors = freeform.GetColors(); var positions = new Vector2[] { new Vector2(0.80f, 0.10f), new Vector2(0.35f, 0.25f), new Vector2(0.20f, 0.90f), new Vector2(0.65f, 0.75f), }; using (var gradient = CanvasBitmap.CreateFromBytes(device, ChatBackgroundFreeform.GenerateGradientData(50, 50, colors, positions), 50, 50, DirectXPixelFormat.B8G8R8A8UIntNormalized)) using (var cache = await PlaceholderHelper.GetPatternBitmapAsync(device, null, background.Document.DocumentValue)) { using (var scale = new ScaleEffect { Source = gradient, BorderMode = EffectBorderMode.Hard, Scale = new Vector2(640f / 50f, 640f / 50f) }) using (var colorize = new TintEffect { Source = cache, Color = Color.FromArgb(0x76, 00, 00, 00) }) using (var tile = new BorderEffect { Source = colorize, ExtendX = CanvasEdgeBehavior.Wrap, ExtendY = CanvasEdgeBehavior.Wrap }) using (var effect = new BlendEffect { Foreground = tile, Background = scale, Mode = BlendEffectMode.Overlay }) { session.DrawImage(effect, new Rect(0, 0, 640, 640), new Rect(0, 0, 640, 640)); } } } } } bitmaps.Add(sfondo); var width = (int)(512d * conversion.Scale); var height = (int)(512d * conversion.Scale); var animation = await Task.Run(() => LottieAnimation.LoadFromFile(sticker.Local.Path, new Windows.Graphics.SizeInt32 { Width = width, Height = height }, false, null)); if (animation == null) { _protoService.Send(new FinishFileGeneration(update.GenerationId, new Error(500, "FILE_GENERATE_LOCATION_INVALID Can't load Lottie animation"))); return; } var composition = new MediaComposition(); var layer = new MediaOverlayLayer(); var buffer = ArrayPool <byte> .Shared.Rent(width *height * 4); var framesPerUpdate = animation.FrameRate < 60 ? 1 : 2; var duration = TimeSpan.Zero; for (int i = 0; i < animation.TotalFrame; i += framesPerUpdate) { var bitmap = CanvasBitmap.CreateFromBytes(device, buffer, width, height, DirectXPixelFormat.B8G8R8A8UIntNormalized); animation.RenderSync(bitmap, i); var clip = MediaClip.CreateFromSurface(bitmap, TimeSpan.FromMilliseconds(1000d / 30d)); var overlay = new MediaOverlay(clip, new Rect(320 - (width / 2d), 320 - (height / 2d), width, height), 1); overlay.Delay = duration; layer.Overlays.Add(overlay); duration += clip.OriginalDuration; bitmaps.Add(bitmap); } composition.OverlayLayers.Add(layer); composition.Clips.Add(MediaClip.CreateFromSurface(sfondo, duration)); var temp = await _protoService.GetFileAsync(update.DestinationPath); var profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto); profile.Audio = null; profile.Video.Bitrate = 1800000; profile.Video.Width = 640; profile.Video.Height = 640; profile.Video.FrameRate.Numerator = 30; profile.Video.FrameRate.Denominator = 1; var progress = composition.RenderToFileAsync(temp, MediaTrimmingPreference.Precise, profile); progress.Progress = (result, delta) => { _protoService.Send(new SetFileGenerationProgress(update.GenerationId, 100, (int)delta)); }; var result = await progress; if (result == TranscodeFailureReason.None) { _protoService.Send(new FinishFileGeneration(update.GenerationId, null)); } else { _protoService.Send(new FinishFileGeneration(update.GenerationId, new Error(500, result.ToString()))); } ArrayPool <byte> .Shared.Return(buffer); foreach (var bitmap in bitmaps) { bitmap.Dispose(); } } catch (Exception ex) { _protoService.Send(new FinishFileGeneration(update.GenerationId, new Error(500, "FILE_GENERATE_LOCATION_INVALID " + ex.ToString()))); } }