Skip to content

Commit

Permalink
Use image pipeline in markdown renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
erri120 committed Dec 16, 2024
1 parent 478db3c commit ab2452f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using JetBrains.Annotations;
using Markdown.Avalonia.Plugins;
using Markdown.Avalonia.Utils;
using Microsoft.Extensions.Logging;
using NexusMods.Abstractions.Resources;
using NexusMods.Abstractions.UI;
using NexusMods.App.UI.Extensions;
using NexusMods.CrossPlatform.Process;
using NexusMods.Hashing.xxHash3;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

Expand All @@ -19,8 +21,8 @@ namespace NexusMods.App.UI.Controls.MarkdownRenderer;
public class MarkdownRendererViewModel : AViewModel<IMarkdownRendererViewModel>, IMarkdownRendererViewModel
{
private readonly ILogger _logger;
private readonly IImageCache _imageCache;
private readonly HttpClient _httpClient;
private readonly IResourceLoader<Uri, Bitmap> _remoteImagePipeline;

[Reactive] public string Contents { get; set; } = string.Empty;
[Reactive] public Uri? MarkdownUri { get; set; }
Expand All @@ -31,14 +33,14 @@ public class MarkdownRendererViewModel : AViewModel<IMarkdownRendererViewModel>,
public ReactiveCommand<string, Unit> OpenLinkCommand { get; }

public MarkdownRendererViewModel(
IServiceProvider serviceProvider,
ILogger<MarkdownRendererViewModel> logger,
IOSInterop osInterop,
IImageCache imageCache,
HttpClient httpClient)
{
_logger = logger;
_imageCache = imageCache;
_httpClient = httpClient;
_remoteImagePipeline = ImagePipelines.GetMarkdownRendererRemoteImagePipeline(serviceProvider);

PathResolver = new PathResolverImpl(this);
ImageResolverPlugin = new ImageResolvePluginImpl(new ImageResolverImpl(this));
Expand Down Expand Up @@ -120,14 +122,11 @@ private async Task<string> FetchMarkdown(Uri uri, CancellationToken cancellation
return await FetchRemoteImage(uri, cancellationToken);
}

private async Task<Stream?> FetchRemoteImage(Uri uri, CancellationToken cancellationToken = default)
private Task<Stream?> FetchRemoteImage(Uri uri, CancellationToken cancellationToken = default)
{
var hash = await _imageCache.Prefetch(new ImageIdentifier(uri), cancellationToken);
var hashValue = hash.Value;

var bytes = BitConverter.GetBytes(hashValue);
var bytes = Encoding.UTF8.GetBytes(uri.ToString());
var ms = new MemoryStream(bytes, writable: false);
return ms;
return Task.FromResult<Stream?>(ms);
}

private class ImageResolvePluginImpl : IMdAvPlugin
Expand Down Expand Up @@ -191,14 +190,12 @@ public ImageResolverImpl(MarkdownRendererViewModel parent)

public async Task<IImage?> Load(Stream stream)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(ulong));
stream.ReadExactly(bytes);

var hashValue = BitConverter.ToUInt64(bytes);
var hash = Hash.FromULong(hashValue);
using var sr = new StreamReader(stream, Encoding.UTF8);
var url = await sr.ReadToEndAsync();
var uri = new Uri(url, UriKind.Absolute);

var image = await _parent._imageCache.GetImage(new ImageIdentifier(hash), CancellationToken.None);
return image;
var resource = await _parent._remoteImagePipeline.LoadResourceAsync(uri, CancellationToken.None);
return resource.Data;
}
}
}
21 changes: 21 additions & 0 deletions src/NexusMods.App.UI/ImagePipelines.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public static class ImagePipelines
private const string UserAvatarPipelineKey = nameof(UserAvatarPipelineKey);
private const string GuidedInstallerRemoteImagePipelineKey = nameof(GuidedInstallerRemoteImagePipelineKey);
private const string GuidedInstallerFileImagePipelineKey = nameof(GuidedInstallerFileImagePipelineKey);
private const string MarkdownRendererRemoteImagePipelineKey = nameof(MarkdownRendererRemoteImagePipelineKey);

private static readonly Bitmap CollectionTileFallback = new(AssetLoader.Open(new Uri("avares://NexusMods.App.UI/Assets/collection-tile-fallback.png")));
private static readonly Bitmap CollectionBackgroundFallback = new(AssetLoader.Open(new Uri("avares://NexusMods.App.UI/Assets/black-box.png")));
Expand Down Expand Up @@ -74,6 +75,12 @@ public static IServiceCollection AddImagePipelines(this IServiceCollection servi
implementationFactory: static (serviceProvider, _) => CreateGuidedInstallerFileImagePipeline(
fileStore: serviceProvider.GetRequiredService<IFileStore>()
)
)
.AddKeyedSingleton<IResourceLoader<Uri, Bitmap>>(
serviceKey: MarkdownRendererRemoteImagePipelineKey,
implementationFactory: static (serviceProvider, _) => CreateMarkdownRendererRemoteImagePipeline(
httpClient: serviceProvider.GetRequiredService<HttpClient>()
)
);
}

Expand Down Expand Up @@ -102,6 +109,11 @@ public static IResourceLoader<Hash, Lifetime<Bitmap>> GetGuidedInstallerFileImag
return serviceProvider.GetRequiredKeyedService<IResourceLoader<Hash, Lifetime<Bitmap>>>(serviceKey: GuidedInstallerFileImagePipelineKey);
}

public static IResourceLoader<Uri, Bitmap> GetMarkdownRendererRemoteImagePipeline(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredKeyedService<IResourceLoader<Uri, Bitmap>>(serviceKey: MarkdownRendererRemoteImagePipelineKey);
}

private static IResourceLoader<EntityId, Bitmap> CreateUserAvatarPipeline(
HttpClient httpClient,
IConnection connection)
Expand Down Expand Up @@ -185,6 +197,15 @@ private static IResourceLoader<Uri, Lifetime<Bitmap>> CreateGuidedInstallerRemot
return pipeline;
}

private static IResourceLoader<Uri, Bitmap> CreateMarkdownRendererRemoteImagePipeline(HttpClient httpClient)
{
var pipeline = new HttpLoader(httpClient)
.Decode(decoderType: DecoderType.Skia)
.ToAvaloniaBitmap();

return pipeline;
}

private static IResourceLoader<Hash, Lifetime<Bitmap>> CreateGuidedInstallerFileImagePipeline(IFileStore fileStore)
{
var pipeline = new FileStoreLoader(fileStore)
Expand Down

0 comments on commit ab2452f

Please sign in to comment.