/// <inheritdoc /> public override async Task InvokeAsync(ILoadingContext <ImageSource> context, LoadingPipeDelegate <ImageSource> next, CancellationToken cancellationToken = default) { if (context.Current is Stream stream) { if (!stream.CanSeek) { var memoryStream = new MemoryStream(); await stream.CopyToAsync(memoryStream); if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. stream.Dispose(); } memoryStream.Seek(0, SeekOrigin.Begin); stream = memoryStream; } var isSvg = IsSvg(stream); var tcs = new TaskCompletionSource <object?>(); context.InvokeOnUIThread(async() => { try { if (isSvg) { var bitmap = new SvgImageSource(); context.AttachSource(bitmap); var svgImageLoadStatus = await bitmap.SetSourceAsync(stream.AsRandomAccessStream()); if (svgImageLoadStatus != SvgImageSourceLoadStatus.Success) { throw new SvgImageFailedStatusException(svgImageLoadStatus); } cancellationToken.ThrowIfCancellationRequested(); context.Current = bitmap; } else { // https://docs.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-animations-and-media?redirectedfrom=MSDN#right-sized-decoding // Set source after attached to the XAML tree var bitmap = new BitmapImage(); context.AttachSource(bitmap); await bitmap.SetSourceAsync(stream.AsRandomAccessStream()); cancellationToken.ThrowIfCancellationRequested(); context.Current = bitmap; } tcs.SetResult(null); } catch (Exception ex) { tcs.SetException(ex); } }); await tcs.Task; } await next(context, cancellationToken); }
/// <inheritdoc /> public override async Task InvokeAsync(ILoadingContext <ICompositionSurface> context, LoadingPipeDelegate <ICompositionSurface> next, CancellationToken cancellationToken = default) { if (context.Current is Stream stream) { var tcs = new TaskCompletionSource <LoadedImageSurface>(); var imageSurface = LoadedImageSurface.StartLoadFromStream(stream.AsRandomAccessStream()); context.AttachSource(imageSurface); TypedEventHandler <LoadedImageSurface, LoadedImageSourceLoadCompletedEventArgs> handler = null !; handler = (sender, args) => { imageSurface.LoadCompleted -= handler; switch (args.Status) { case LoadedImageSourceLoadStatus.Success: tcs.SetResult(sender); break; default: tcs.SetException(new ImageSurfaceFailedStatusException(args.Status)); break; } }; imageSurface.LoadCompleted += handler; context.Current = await tcs.Task; } await next(context, cancellationToken); }
/// <inheritdoc /> public override async Task InvokeAsync(ILoadingContext <TSource> context, LoadingPipeDelegate <TSource> next, CancellationToken cancellationToken = default) { if (IsInDesignMode) { await next(context, cancellationToken); return; } var cacheKey = context.Current; if (cacheKey is string || cacheKey is Uri) { if (MemoryCache.TryGetValue(cacheKey, out var cacheValue)) { context.Current = cacheValue; context.AttachSource(cacheValue); return; } await next(context, cancellationToken); if (context.Current is TSource finalValue) { MemoryCache[cacheKey] = finalValue; } return; } await next(context, cancellationToken); }
/// <inheritdoc /> public override async Task InvokeAsync(ILoadingContext <ImageSource> context, LoadingPipeDelegate <ImageSource> next, CancellationToken cancellationToken = default) { if (context.Current is Stream stream) { if (!stream.CanSeek) { var memoryStream = new MemoryStream(); await stream.CopyToAsync(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); stream = memoryStream; } var isWebP = IsWebP(stream); var tcs = new TaskCompletionSource <ImageSource>(); await Task.Run(() => { Image webPImage = null; if (isWebP) { var webPFormat = new WebPFormat(); webPImage = webPFormat.Load(stream); } if (webPImage != null) { var webPMemoryStream = new MemoryStream(); webPImage.Save(webPMemoryStream, ImageFormat.Png); stream = webPMemoryStream; } stream.Seek(0, SeekOrigin.Begin); try { var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; bitmap.EndInit(); bitmap.Freeze(); context.UIContext.Send(state => { context.AttachSource(bitmap); }, null); tcs.SetResult(bitmap); } catch (Exception ex) { tcs.SetException(ex); } }, cancellationToken); context.Current = await tcs.Task; } await next(context, cancellationToken); }
/// <inheritdoc /> public override async Task InvokeAsync(ILoadingContext <ImageSource> context, LoadingPipeDelegate <ImageSource> next, CancellationToken cancellationToken = default) { if (context.Current is Stream stream) { if (!stream.CanSeek) { var memoryStream = new MemoryStream(); #if NETCOREAPP3_1 await stream.CopyToAsync(memoryStream, cancellationToken); if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. await stream.DisposeAsync(); } #else await stream.CopyToAsync(memoryStream); if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. stream.Dispose(); } #endif memoryStream.Seek(0, SeekOrigin.Begin); stream = memoryStream; } var tcs = new TaskCompletionSource <ImageSource>(); await Task.Run(() => { stream.Seek(0, SeekOrigin.Begin); try { var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; bitmap.EndInit(); bitmap.Freeze(); context.InvokeOnUIThread(() => { context.AttachSource(bitmap); }); tcs.SetResult(bitmap); } catch (Exception ex) { tcs.SetException(ex); } }, cancellationToken); context.Current = await tcs.Task; } await next(context, cancellationToken); }
/// <inheritdoc /> public override async Task InvokeAsync(ILoadingContext <ImageExSource> context, LoadingPipeDelegate <ImageExSource> next, CancellationToken cancellationToken = default) { if (context.Current is Stream stream) { if (!stream.CanSeek) { var memoryStream = new MemoryStream(); #if NETCOREAPP3_1 await stream.CopyToAsync(memoryStream, cancellationToken); if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. await stream.DisposeAsync(); } #else await stream.CopyToAsync(memoryStream); if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. stream.Dispose(); } #endif memoryStream.Seek(0, SeekOrigin.Begin); stream = memoryStream; } var tcs = new TaskCompletionSource <ImageExSource>(); await Task.Run(() => { using var codec = SKCodec.Create(stream, out var codecResult); if (codecResult != SKCodecResult.Success) { tcs.SetException(new Exception(codecResult.ToString())); return; } var codecInfo = codec.Info; var frameCount = codec.FrameCount; if (frameCount <= 0) { var source = new ImageExSource { Frames = new ImageExFrame[1], RepetitionCount = codec.RepetitionCount, Width = codecInfo.Width, Height = codecInfo.Height }; var bitmap = new SKBitmap(codecInfo); var pointer = bitmap.GetPixels(); codec.GetPixels(bitmap.Info, pointer); source.Frames[0] = new ImageExFrame { Bitmap = bitmap }; context.InvokeOnUIThread(() => { context.AttachSource(source); }); tcs.SetResult(source); } else { var source = new ImageExSource { Frames = new ImageExFrame[frameCount], RepetitionCount = codec.RepetitionCount, Width = codecInfo.Width, Height = codecInfo.Height }; for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { var bitmap = new SKBitmap(codecInfo); var pointer = bitmap.GetPixels(); var codecOptions = new SKCodecOptions(frameIndex); codec.GetPixels(bitmap.Info, pointer, codecOptions); var frameInfo = codec.FrameInfo[frameIndex]; var duration = frameInfo.Duration; source.Frames[frameIndex] = new ImageExFrame { Bitmap = bitmap, Duration = duration }; } context.InvokeOnUIThread(() => { context.AttachSource(source); }); tcs.SetResult(source); } }, cancellationToken); context.Current = await tcs.Task; #if NETCOREAPP3_1 if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. await stream.DisposeAsync(); } #else if (!ReferenceEquals(stream, context.OriginSource)) { // if the stream generated by the pipe then dispose it. stream.Dispose(); } #endif } await next(context, cancellationToken); }