소스 검색

[Avalonia] base64 copy, paste and loading updates

Ruben 1 년 전
부모
커밋
8f2e415a78

+ 40 - 16
src/PicView.Avalonia/Clipboard/ClipboardHelper.cs

@@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Input;
 using Avalonia.Media.Imaging;
 using Avalonia.Platform.Storage;
+using Avalonia.Svg.Skia;
 using PicView.Avalonia.Navigation;
 using PicView.Avalonia.ViewModels;
 using PicView.Core.Localization;
@@ -27,32 +28,55 @@ public static class ClipboardHelper
     }
 
     public static async Task CopyImageToClipboard(string path)
+    {
+        // TODO: Implement CopyImageToClipboard
+    }
+
+    public static async Task CopyBase64ToClipboard(string path, MainViewModel vm)
     {
         if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
         {
             return;
         }
-        var dataObject = new DataObject();
-        dataObject.Set(DataFormats.Files, new[] { path });
-        await desktop.MainWindow.Clipboard.SetDataObjectAsync(dataObject);
-    }
+        var clipboard = desktop.MainWindow.Clipboard;
+        var base64 = string.Empty;
+        if (string.IsNullOrWhiteSpace(path))
+        {
+            switch (vm.ImageType)
+            {
+                case ImageType.AnimatedBitmap:
+                    throw new ArgumentOutOfRangeException();
+                case ImageType.Bitmap:
+                    if (vm.ImageSource is not Bitmap bitmap)
+                    {
+                        throw new ArgumentOutOfRangeException();
+                    }
+                    var stream = new MemoryStream();
+                    bitmap.Save(stream, quality: 100);
+                    base64 = Convert.ToBase64String(stream.ToArray());
+                    break;
+                case ImageType.Svg:
+                    throw new ArgumentOutOfRangeException();
+                default:
+                    throw new ArgumentOutOfRangeException();
+            }
+        }
+        else
+        {
+            base64 = Convert.ToBase64String(await File.ReadAllBytesAsync(path));
+        }
 
-    public static async Task CopyBase64ToClipboard(string path)
-    {
-        throw new NotImplementedException();
+        if (string.IsNullOrEmpty(base64))
+        {
+            return;
+        }
+
+        await clipboard.SetTextAsync(base64);
     }   
 
     public static async Task CutFile(string path)
     {
-        if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
-        {
-            return;
-        }
-        var clipboard = desktop.MainWindow.Clipboard;
-        var dataObject = new DataObject();
-        dataObject.Set(DataFormats.Files, new[] { path });
-        await clipboard.ClearAsync();
-        await clipboard.SetDataObjectAsync(dataObject);
+        // TODO: Implement CutFile
     }
     
     public static async Task Paste(MainViewModel vm)

+ 33 - 15
src/PicView.Avalonia/Navigation/NavigationHelper.cs

@@ -309,22 +309,40 @@ public static class NavigationHelper
         vm.FileInfo = null;
         await Task.Run(async () =>
         {
-            var magickImage = await ImageDecoder.Base64ToMagickImage(base64).ConfigureAwait(false);
-            magickImage.Format = MagickFormat.Png;
-            await using var memoryStream = new MemoryStream();
-            await magickImage.WriteAsync(memoryStream);
-            memoryStream.Position = 0;
-            var bitmap = new Bitmap(memoryStream);
-            var imageModel = new ImageModel
+            // TODO: Handle base64 if it's SVG image
+            try
             {
-                Image = bitmap,
-                PixelWidth = bitmap?.PixelSize.Width ?? 0,
-                PixelHeight = bitmap?.PixelSize.Height ?? 0,
-                ImageType = ImageType.Bitmap
-            };
-            SetSingleImage(imageModel.Image as Bitmap, TranslationHelper.Translation.Base64Image, vm);
-            ExifHandling.SetImageModel(imageModel, vm);
-            ExifHandling.UpdateExifValues(imageModel, vm);
+                var magickImage = await ImageDecoder.Base64ToMagickImage(base64).ConfigureAwait(false);
+                magickImage.Format = MagickFormat.Png;
+                await using var memoryStream = new MemoryStream();
+                await magickImage.WriteAsync(memoryStream);
+                memoryStream.Position = 0;
+                var bitmap = new Bitmap(memoryStream);
+                var imageModel = new ImageModel
+                {
+                    Image = bitmap,
+                    PixelWidth = bitmap?.PixelSize.Width ?? 0,
+                    PixelHeight = bitmap?.PixelSize.Height ?? 0,
+                    ImageType = ImageType.Bitmap
+                };
+                SetSingleImage(imageModel.Image as Bitmap, TranslationHelper.Translation.Base64Image, vm);
+                ExifHandling.SetImageModel(imageModel, vm);
+                ExifHandling.UpdateExifValues(imageModel, vm);
+            }
+            catch (Exception e)
+            {
+                #if DEBUG
+                Console.WriteLine("LoadPicFromBase64Async exception = \n" + e.Message);
+                #endif
+                if (vm.FileInfo is not null && vm.FileInfo.Exists)
+                {
+                    await LoadPicFromFile(vm.FileInfo.FullName, vm, vm.FileInfo);
+                }
+                else
+                {
+                    ErrorHandling.ShowStartUpMenu(vm);
+                }
+            }
         });
         vm.IsLoading = false;
     }

+ 1 - 1
src/PicView.Avalonia/UI/FunctionsHelper.cs

@@ -742,7 +742,7 @@ public static class FunctionsHelper
         {
             return;
         }
-        await ClipboardHelper.CopyBase64ToClipboard(Vm.FileInfo.FullName);
+        await ClipboardHelper.CopyBase64ToClipboard(Vm.FileInfo.FullName, vm: Vm);
     }
 
     public static async Task DuplicateFile()

+ 4 - 5
src/PicView.Avalonia/ViewModels/MainViewModel.cs

@@ -383,6 +383,7 @@ public class MainViewModel : ViewModelBase
     public ReactiveCommand<Unit, Unit>? OpenLastFileCommand { get; }
     public ReactiveCommand<Unit, Unit>? PasteCommand { get; }
     public ReactiveCommand<string, Unit>? CopyFileCommand { get; }
+    public ReactiveCommand<string, Unit>? CopyBase64Command { get; }
     public ReactiveCommand<string, Unit>? CopyFilePathCommand { get; }
     public ReactiveCommand<string, Unit>? FilePropertiesCommand { get; }
     public ReactiveCommand<string, Unit>? CopyImageCommand { get; }
@@ -1412,15 +1413,11 @@ public class MainViewModel : ViewModelBase
     
     private async Task CopyBase64Task(string path)
     {
-        if (string.IsNullOrWhiteSpace(path))
-        {
-            return;
-        }
         if (PlatformService is null)
         {
             return;
         }
-        await ClipboardHelper.CopyBase64ToClipboard(path);
+        await ClipboardHelper.CopyBase64ToClipboard(path, this);
     }
     
     private async Task CutFileTask(string path)
@@ -1746,6 +1743,8 @@ public class MainViewModel : ViewModelBase
         FilePropertiesCommand = ReactiveCommand.CreateFromTask<string>(ShowFilePropertiesTask);
 
         CopyImageCommand = ReactiveCommand.CreateFromTask<string>(CopyImageTask);
+        
+        CopyBase64Command = ReactiveCommand.CreateFromTask<string>(CopyBase64Task);
 
         CutCommand = ReactiveCommand.CreateFromTask<string>(CutFileTask);
 

+ 8 - 3
src/PicView.Avalonia/Views/MainView.axaml

@@ -427,7 +427,7 @@
                             Width="12" />
                     </MenuItem.Icon>
                 </MenuItem>
-                <MenuItem>
+                <MenuItem Command="{CompiledBinding CopyBase64Command}" CommandParameter="{CompiledBinding FileInfo.FullName, FallbackValue=''}">
                     <MenuItem.Header>
                         <TextBlock>
                             <Run Text="{CompiledBinding Copy, Mode=OneWay}" />
@@ -464,7 +464,8 @@
                     CommandParameter="{CompiledBinding FileInfo.FullName,
                                                        FallbackValue=''}"
                     Header="{CompiledBinding FileCut,
-                                             Mode=OneWay}">
+                                             Mode=OneWay}"
+                    IsEnabled="False">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource CutGeometry}"
@@ -490,7 +491,11 @@
                         Width="12" />
                 </MenuItem.Icon>
             </MenuItem>
-            <MenuItem Command="{CompiledBinding CopyImageCommand}" Header="{CompiledBinding CopyImage, Mode=OneWay}">
+            <MenuItem
+                Command="{CompiledBinding CopyImageCommand}"
+                Header="{CompiledBinding CopyImage,
+                                         Mode=OneWay}"
+                IsEnabled="False">
                 <MenuItem.Icon>
                     <Path
                         Data="M384 336H192c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16l140.1 0L400 115.9V320c0 8.8-7.2 16-16 16zM192 384H384c35.3 0 64-28.7 64-64V115.9c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1H192c-35.3 0-64 28.7-64 64V320c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H256c35.3 0 64-28.7 64-64V416H272v32c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H96V128H64z"