WIP Image imports and file access
This commit is contained in:
@@ -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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
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<IDispatcher, AvaloniaDispatcher>();
|
||||||
|
|
||||||
services.AddTransient<IContentTemplate, ContentTemplate>();
|
services.AddTransient<IContentTemplate, ContentTemplate>();
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Toolkit.Avalonia;
|
||||||
|
|
||||||
|
public interface ITopLevelProvider
|
||||||
|
{
|
||||||
|
TopLevel? Get();
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public record Activated
|
public record Activated
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ public record Delete
|
|||||||
|
|
||||||
public static DeleteEventArgs<TSender> As<TSender>() where TSender : new() =>
|
public static DeleteEventArgs<TSender> As<TSender>() where TSender : new() =>
|
||||||
new(new TSender());
|
new(new TSender());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public interface IFileProvider
|
||||||
|
{
|
||||||
|
Task<IReadOnlyCollection<string>> SelectFiles(FileFilter filter);
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IFileSelector
|
|
||||||
{
|
|
||||||
Task<IEnumerable<string>> SelectFiles(FileFilter filter);
|
|
||||||
}
|
|
||||||
@@ -123,7 +123,7 @@ public static class IHostBuilderExtension
|
|||||||
IFileInfo? fileInfo = null;
|
IFileInfo? fileInfo = null;
|
||||||
if (provider.GetService<IHostEnvironment>() is IHostEnvironment hostEnvironment)
|
if (provider.GetService<IHostEnvironment>() is IHostEnvironment hostEnvironment)
|
||||||
{
|
{
|
||||||
IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider;
|
Microsoft.Extensions.FileProviders.IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider;
|
||||||
fileInfo = fileProvider.GetFileInfo(path);
|
fileInfo = fileProvider.GetFileInfo(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public interface IImageDescriptor
|
||||||
|
{
|
||||||
|
public object Image { get; }
|
||||||
|
|
||||||
|
public int Width { get; }
|
||||||
|
|
||||||
|
public int Height { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public interface IImageProvider
|
||||||
|
{
|
||||||
|
Task<IImageDescriptor> Get(string filePath,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
bool maintainAspectRatio = false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public record ImageDescriptor(object Image, int Width, int Height) :
|
||||||
|
IImageDescriptor;
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public record RequestEventArgs<TValue>(TValue? Value = default);
|
public record RequestEventArgs<TSender>(TSender? Sender = default);
|
||||||
|
|||||||
Reference in New Issue
Block a user