Browse Source

Implemented async startup preview images

CPKreuz 1 year ago
parent
commit
8174c1234a

+ 0 - 70
src/PixiEditor/Models/UserData/RecentlyOpenedDocument.cs

@@ -30,7 +30,6 @@ internal class RecentlyOpenedDocument : ObservableObject
             SetProperty(ref filePath, value);
             SetProperty(ref filePath, value);
             this.OnPropertyChanged(nameof(FileName));
             this.OnPropertyChanged(nameof(FileName));
             this.OnPropertyChanged(nameof(FileExtension));
             this.OnPropertyChanged(nameof(FileExtension));
-            PreviewBitmap = null;
         }
         }
     }
     }
 
 
@@ -61,77 +60,8 @@ internal class RecentlyOpenedDocument : ObservableObject
         }
         }
     }
     }
 
 
-    public Texture PreviewBitmap
-    {
-        get
-        {
-            if (previewBitmap == null && !Corrupt)
-            {
-                previewBitmap = LoadPreviewBitmap();
-            }
-
-            return previewBitmap;
-        }
-        private set => SetProperty(ref previewBitmap, value);
-    }
-
     public RecentlyOpenedDocument(string path)
     public RecentlyOpenedDocument(string path)
     {
     {
         FilePath = path;
         FilePath = path;
     }
     }
-
-    private Texture? LoadPreviewBitmap()
-    {
-        if (!File.Exists(FilePath))
-        {
-            return null;
-        }
-
-        if (FileExtension == ".pixi")
-        {
-            try
-            {
-                return Importer.GetPreviewTexture(FilePath);
-            }
-            catch
-            {
-                return null;
-            }
-        }
-
-        if (SupportedFilesHelper.IsExtensionSupported(FileExtension))
-        {
-            Texture bitmap = null;
-
-            try
-            {
-                bitmap = Texture.Load(FilePath);
-            }
-            catch (RecoverableException)
-            {
-                corrupt = true;
-                return null;
-            }
-
-            if (bitmap == null) //prevent crash
-                return null;
-
-            return DownscaleToMaxSize(bitmap);
-        }
-
-        return null;
-    }
-
-    private Texture DownscaleToMaxSize(Texture bitmap)
-    {
-        if (bitmap.Size.X > Constants.MaxPreviewWidth || bitmap.Size.Y > Constants.MaxPreviewHeight)
-        {
-            double factor = Math.Min(Constants.MaxPreviewWidth / (double)bitmap.Size.X, Constants.MaxPreviewHeight / (double)bitmap.Size.Y);
-            var scaledBitmap = bitmap.CreateResized(new VecI((int)(bitmap.Size.X * factor), (int)(bitmap.Size.Y * factor)),
-                ResizeMethod.HighQuality);
-            return scaledBitmap;
-        }
-
-        return bitmap;
-    }
 }
 }

+ 144 - 0
src/PixiEditor/Views/Visuals/PixiFilePreviewImage.cs

@@ -0,0 +1,144 @@
+using System.Drawing;
+using Avalonia;
+using Avalonia.Threading;
+using FFMpegCore.Enums;
+using PixiEditor.DrawingApi.Core;
+using PixiEditor.Extensions.Exceptions;
+using PixiEditor.Helpers;
+using PixiEditor.Models;
+using PixiEditor.Models.IO;
+using PixiEditor.Numerics;
+using PixiEditor.Parser;
+using Image = Avalonia.Controls.Image;
+
+namespace PixiEditor.Views.Visuals;
+
+internal class PixiFilePreviewImage : SurfaceControl
+{
+    public static readonly StyledProperty<string> FilePathProperty =
+        AvaloniaProperty.Register<PixiFilePreviewImage, string>(nameof(FilePath));
+
+    public static readonly StyledProperty<VecI> ImageSizeProperty =
+        AvaloniaProperty.Register<PixiFilePreviewImage, VecI>(nameof(VecI));
+
+    public static readonly StyledProperty<bool> CorruptProperty =
+        AvaloniaProperty.Register<PixiFilePreviewImage, bool>(nameof(Corrupt));
+
+    public string FilePath
+    {
+        get => GetValue(FilePathProperty);
+        set => SetValue(FilePathProperty, value);
+    }
+    
+    public VecI ImageSize
+    {
+        get => GetValue(ImageSizeProperty);
+        set => SetValue(ImageSizeProperty, value);
+    }
+
+    public bool Corrupt
+    {
+        get => GetValue(CorruptProperty);
+        set => SetValue(CorruptProperty, value);
+    }
+
+    static PixiFilePreviewImage()
+    {
+        FilePathProperty.Changed.AddClassHandler<PixiFilePreviewImage>(OnFilePathChanged);
+    }
+
+    private void RunLoadImage()
+    {
+        var path = FilePath;
+
+        Task.Run(() => LoadImage(path));
+    }
+
+    private void LoadImage(string path)
+    {
+        var surface = LoadPreviewSurface(path);
+        
+        Dispatcher.UIThread.Post(() => SetImage(surface, surface.Size));
+    }
+
+    private void SetImage(Surface surface, VecI size)
+    {
+        Surface = surface;
+        ImageSize = size;
+    }
+
+    private static void OnFilePathChanged(PixiFilePreviewImage previewImage, AvaloniaPropertyChangedEventArgs args)
+    {
+        if (args.NewValue == null)
+        {
+            previewImage.Surface = null;
+            return;
+        }
+        
+        previewImage.RunLoadImage();
+    }
+    
+    private Surface? LoadPreviewSurface(string filePath)
+    {
+        if (!File.Exists(filePath))
+        {
+            return null;
+        }
+        
+        var fileExtension = Path.GetExtension(filePath);
+
+        if (fileExtension == ".pixi")
+        {
+            try
+            {
+                return Importer.GetPreviewSurface(filePath);
+            }
+            catch
+            {
+                SetCorrupt();
+                return null;
+            }
+        }
+
+        if (SupportedFilesHelper.IsExtensionSupported(fileExtension))
+        {
+            Surface bitmap = null;
+
+            try
+            {
+                bitmap = Surface.Load(filePath);
+            }
+            catch (RecoverableException)
+            {
+                SetCorrupt();
+            }
+
+            if (bitmap == null) //prevent crash
+                return null;
+
+            return DownscaleToMaxSize(bitmap);
+        }
+
+        return null;
+
+        void SetCorrupt()
+        {
+            Dispatcher.UIThread.Post(() => Corrupt = true);
+        }
+    }
+
+    private static Surface DownscaleToMaxSize(Surface bitmap)
+    {
+        if (bitmap.Size.X > Constants.MaxPreviewWidth || bitmap.Size.Y > Constants.MaxPreviewHeight)
+        {
+            double factor = Math.Min(Constants.MaxPreviewWidth / (double)bitmap.Size.X, Constants.MaxPreviewHeight / (double)bitmap.Size.Y);
+            var scaledBitmap = bitmap.Resize(new VecI((int)(bitmap.Size.X * factor), (int)(bitmap.Size.Y * factor)), ResizeMethod.HighQuality);
+            
+            bitmap.Dispose();
+            return scaledBitmap;
+        }
+    
+        return bitmap;
+    }
+    
+}

+ 6 - 5
src/PixiEditor/Views/Windows/HelloTherePopup.axaml

@@ -130,19 +130,20 @@
                                                     CommandParameter="{Binding FilePath}"
                                                     CommandParameter="{Binding FilePath}"
                                                     x:Name="fileButton">
                                                     x:Name="fileButton">
                                                 <Grid Width="100" Height="100">
                                                 <Grid Width="100" Height="100">
-                                                    <visuals:TextureControl
-                                                        Texture="{Binding PreviewBitmap}"
+                                                    <visuals:PixiFilePreviewImage
+                                                        FilePath="{Binding FilePath}"
+                                                        Corrupt="{Binding Corrupt}"
                                                         Margin="10"
                                                         Margin="10"
                                                         Stretch="Uniform"
                                                         Stretch="Uniform"
                                                         x:Name="image">
                                                         x:Name="image">
                                                         <ui:RenderOptionsBindable.BitmapInterpolationMode>
                                                         <ui:RenderOptionsBindable.BitmapInterpolationMode>
                                                             <MultiBinding
                                                             <MultiBinding
                                                                 Converter="{converters:WidthToBitmapScalingModeConverter}">
                                                                 Converter="{converters:WidthToBitmapScalingModeConverter}">
-                                                                <Binding Path="PreviewBitmap.Size.X" />
-                                                                <Binding ElementName="image" Path="Width" />
+                                                                <Binding Path="ImageSize.X" ElementName="image" />
+                                                                <Binding Path="Width" ElementName="image" />
                                                             </MultiBinding>
                                                             </MultiBinding>
                                                         </ui:RenderOptionsBindable.BitmapInterpolationMode>
                                                         </ui:RenderOptionsBindable.BitmapInterpolationMode>
-                                                    </visuals:TextureControl>
+                                                    </visuals:PixiFilePreviewImage>
                                                     <Border Grid.Row="1" Height="8" Width="8" x:Name="extensionBorder"
                                                     <Border Grid.Row="1" Height="8" Width="8" x:Name="extensionBorder"
                                                             Margin="5"
                                                             Margin="5"
                                                             Background="{Binding FileExtension, Converter={converters:FileExtensionToColorConverter}}"
                                                             Background="{Binding FileExtension, Converter={converters:FileExtensionToColorConverter}}"