WIP Image imports and file access

This commit is contained in:
TheXamlGuy
2024-06-28 21:03:56 +01:00
parent b5a2bab691
commit f933afc24f
17 changed files with 192 additions and 40 deletions
+32
View File
@@ -0,0 +1,32 @@
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Toolkit.Foundation;
namespace Toolkit.Avalonia;
public class FileProvider(ITopLevelProvider topLevelProvider) :
IFileProvider
{
public async Task<IReadOnlyCollection<string>> SelectFiles(FileFilter filter)
{
if (topLevelProvider.Get() is TopLevel topLevel)
{
IReadOnlyList<IStorageFile> storageFiles = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions()
{
AllowMultiple = filter.AllowMultiple,
FileTypeFilter = new List<FilePickerFileType>
{
new(filter.Name)
{
Patterns = filter.Extensions.Select(x => $"*.{x}").ToList()
}
}
});
return storageFiles.Select(file => file.Path.LocalPath).ToList();
}
return Array.Empty<string>();
}
}
-30
View File
@@ -1,30 +0,0 @@
using Avalonia.Controls;
using Toolkit.Foundation;
namespace Toolkit.Avalonia;
public class FileSelector :
IFileSelector
{
public async Task<IEnumerable<string>> SelectFiles(FileFilter filter)
{
//TopLevel topLevel = TopLevel.GetTopLevel(control);
//var openFileDialog = new OpenFileDialog();
//openFileDialog.Filters.Add(new FileDialogFilter
//{
// Name = filter.Name,
// Extensions = filter.Extensions
//});
//openFileDialog.AllowMultiple = filter.AllowMultiple;
//var results = await openFileDialog.ShowAsync(window as Window);
//if (results != null && results.Length > 0)
//{
// return results.Select(result => result);
//}
return Enumerable.Empty<string>();
}
}
+11
View File
@@ -0,0 +1,11 @@
using Avalonia.Media.Imaging;
namespace Toolkit.Avalonia;
public interface IImageResizer
{
public Bitmap Resize(Stream stream,
int targetWidth,
int targetHeight,
bool maintainAspectRatio);
}
@@ -124,6 +124,11 @@ public static class IServiceCollectionExtensions
public static IServiceCollection AddAvalonia(this IServiceCollection services)
{
services.AddTransient<ITopLevelProvider, TopLevelProvider>();
services.AddTransient<IFileProvider, FileProvider>();
services.AddTransient<IImageProvider, ImageProvider>();
services.AddTransient<IImageResizer, ImageResizer>();
services.AddTransient<IDispatcher, AvaloniaDispatcher>();
services.AddTransient<IContentTemplate, ContentTemplate>();
+8
View File
@@ -0,0 +1,8 @@
using Avalonia.Controls;
namespace Toolkit.Avalonia;
public interface ITopLevelProvider
{
TopLevel? Get();
}
+19
View File
@@ -0,0 +1,19 @@
using Avalonia.Media.Imaging;
using Toolkit.Foundation;
namespace Toolkit.Avalonia;
public class ImageProvider(IImageResizer imageResizer) :
IImageProvider
{
public async Task<IImageDescriptor> Get(string filePath,
int width,
int height,
bool maintainAspectRatio)
{
await using FileStream stream = File.OpenRead(filePath);
Bitmap resizedImage = imageResizer.Resize(stream, width, height, maintainAspectRatio);
return new ImageDescriptor(resizedImage, width, height);
}
}
+53
View File
@@ -0,0 +1,53 @@
using Avalonia.Media.Imaging;
using SkiaSharp;
namespace Toolkit.Avalonia;
public class ImageResizer :
IImageResizer
{
public Bitmap Resize(Stream stream,
int targetWidth,
int targetHeight,
bool maintainAspectRatio)
{
using SKBitmap original = SKBitmap.Decode(stream);
float widthRatio = (float)targetWidth / original.Width;
float heightRatio = (float)targetHeight / original.Height;
float scale = maintainAspectRatio ? Math.Max(widthRatio, heightRatio) : Math.Min(widthRatio, heightRatio);
int newWidth = (int)(original.Width * scale);
int newHeight = (int)(original.Height * scale);
using SKBitmap resized = new(newWidth, newHeight);
using SKCanvas canvas = new(resized);
canvas.Clear(SKColors.Transparent);
canvas.DrawBitmap(original, new SKRect(0, 0, newWidth, newHeight));
SKBitmap cropped;
if (maintainAspectRatio)
{
int cropX = (newWidth - targetWidth) / 2;
int cropY = (newHeight - targetHeight) / 2;
cropped = new SKBitmap(targetWidth, targetHeight);
using SKCanvas croppedCanvas = new(cropped);
SKRect cropRect = new(cropX, cropY, cropX + targetWidth, cropY + targetHeight);
croppedCanvas.Clear(SKColors.Transparent);
croppedCanvas.DrawBitmap(resized, cropRect, new SKRect(0, 0, targetWidth, targetHeight));
}
else
{
cropped = resized;
}
using SKImage image = SKImage.FromBitmap(cropped);
using MemoryStream outputStream = new();
image.Encode(SKEncodedImageFormat.Png, 100).SaveTo(outputStream);
outputStream.Seek(0, SeekOrigin.Begin);
return new Bitmap(outputStream);
}
}
+30
View File
@@ -0,0 +1,30 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace Toolkit.Avalonia;
public class TopLevelProvider :
ITopLevelProvider
{
public TopLevel? Get()
{
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime classicDesktopStyleApplication)
{
if (TopLevel.GetTopLevel(classicDesktopStyleApplication.MainWindow) is TopLevel topLevel)
{
return topLevel;
}
}
if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime singleViewApplication)
{
if (TopLevel.GetTopLevel(singleViewApplication.MainView) is TopLevel topLevel)
{
return topLevel;
}
}
return default;
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
namespace Toolkit.Foundation;
namespace Toolkit.Foundation;
public record Activated
{
+1 -1
View File
@@ -7,4 +7,4 @@ public record Delete
public static DeleteEventArgs<TSender> As<TSender>() where TSender : new() =>
new(new TSender());
}
}
+6
View File
@@ -0,0 +1,6 @@
namespace Toolkit.Foundation;
public interface IFileProvider
{
Task<IReadOnlyCollection<string>> SelectFiles(FileFilter filter);
}
-6
View File
@@ -1,6 +0,0 @@
namespace Toolkit.Foundation;
public interface IFileSelector
{
Task<IEnumerable<string>> SelectFiles(FileFilter filter);
}
+1 -1
View File
@@ -123,7 +123,7 @@ public static class IHostBuilderExtension
IFileInfo? fileInfo = null;
if (provider.GetService<IHostEnvironment>() is IHostEnvironment hostEnvironment)
{
IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider;
Microsoft.Extensions.FileProviders.IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider;
fileInfo = fileProvider.GetFileInfo(path);
}
+10
View File
@@ -0,0 +1,10 @@
namespace Toolkit.Foundation;
public interface IImageDescriptor
{
public object Image { get; }
public int Width { get; }
public int Height { get; }
}
+9
View File
@@ -0,0 +1,9 @@
namespace Toolkit.Foundation;
public interface IImageProvider
{
Task<IImageDescriptor> Get(string filePath,
int width,
int height,
bool maintainAspectRatio = false);
}
+4
View File
@@ -0,0 +1,4 @@
namespace Toolkit.Foundation;
public record ImageDescriptor(object Image, int Width, int Height) :
IImageDescriptor;
+1 -1
View File
@@ -1,3 +1,3 @@
namespace Toolkit.Foundation;
public record RequestEventArgs<TValue>(TValue? Value = default);
public record RequestEventArgs<TSender>(TSender? Sender = default);