Browse Source

Fix only being able to print currently viewed image on macOS

 Refactor macOS print workflow for improved reliability and streamlined code

- Removed temporary PNG saving in `MacPrintEngine`, directly using `ImagePath` for printing.
- Updated `PrintPreviewWindow` logic to initialize with file path and async preview updates.
- Refined `MacPrintInitialization` to handle format conversion and settings setup asynchronously.
- Adjusted platform-specific printing behavior in `FileManager`.
- Removed redundant and unused code related to macOS print preview rendering.
Ruben 1 week ago
parent
commit
b14d8b4492

+ 2 - 16
src/PicView.Avalonia.MacOS/Printing/MacPrintEngine.cs

@@ -62,9 +62,6 @@ public static class MacPrintEngine
                 dest);
         });
 
-        // 5. Save temporary PNG file
-        var tempFile = await SaveToTempPng(rtb);
-
         try
         {
             // 6. Handle PDF exporting or printing
@@ -82,14 +79,14 @@ public static class MacPrintEngine
                     var title = Path.GetFileName(settings.ImagePath.Value) ?? "PicView";
                     var copies = settings.Copies.Value;
 
-                    MacOSPrint.Print(printerName, tempFile, title, copies);
+                    MacOSPrint.Print(printerName, settings.ImagePath.Value, title, copies);
                     break;
                 }
             }
         }
         finally
         {
-            try { File.Delete(tempFile); } catch { /* ignore */ }
+            try { File.Delete(settings.ImagePath.Value); } catch { /* ignore */ }
         }
     }
 
@@ -134,17 +131,6 @@ public static class MacPrintEngine
         };
     }
 
-    private static async ValueTask<string> SaveToTempPng(RenderTargetBitmap rtb)
-    {
-        var tempDir = Path.GetTempPath();
-        var path = Path.Combine(tempDir, $"picview-print-{Guid.NewGuid():N}.png");
-
-        await using var fs = File.Create(path);
-        rtb.Save(fs);
-
-        return path;
-    }
-
     public static IEnumerable<string> GetPaperSizes(string printerName)
         => CupsPaperQuery.GetPaperSizes(printerName);
 

+ 7 - 12
src/PicView.Avalonia.MacOS/Printing/MacPrintInitialization.cs

@@ -1,5 +1,6 @@
 using Avalonia.Media.Imaging;
 using Avalonia.Threading;
+using PicView.Avalonia.ImageHandling;
 using PicView.Avalonia.MacOS.Views;
 using PicView.Avalonia.ViewModels;
 using PicView.Core.MacOS.Printing;
@@ -9,17 +10,8 @@ namespace PicView.Avalonia.MacOS.Printing;
 
 public static class MacPrintInitialization
 {
-    public static void Initialize(MainViewModel vm, string path, PrintPreviewWindow printPreviewWindow)
+    public static async ValueTask Initialize(MainViewModel vm, string path, PrintPreviewWindow printPreviewWindow)
     {
-        // Load image for preview (same as Windows, but using Avalonia Bitmap)
-        if (vm.PicViewer.FileInfo.Value != null && File.Exists(path))
-        {
-            using var fs = File.OpenRead(path);
-            vm.PrintPreview.PreviewImage.Value = new Bitmap(fs);
-            vm.PrintPreview.PageWidth.Value = 650;
-            vm.PrintPreview.PageHeight.Value = 950;
-        }
-
         // 1. Printers via CUPS
         var printers = MacOSPrint.GetAvailablePrinters().ToList(); // includes "Save as PDF" first
         vm.PrintPreview.Printers.Value = printers;
@@ -29,11 +21,14 @@ public static class MacPrintInitialization
         // 2. Paper sizes - from printer or fallback
         vm.PrintPreview.PaperSizes.Value =
             CupsPaperQuery.GetPaperSizes(defaultPrinter).ToList();
+        
+        var commonSupportedFormat = await ImageFormatConverter.ConvertToCommonSupportedFormatAsync(path, vm)
+            .ConfigureAwait(false);
 
         // 3. Build initial PrintSettings
         var currentPrintSettings = new PrintSettings
         {
-            ImagePath = { Value = vm.PicViewer.FileInfo?.Value?.FullName },
+            ImagePath = { Value = commonSupportedFormat },
             PrinterName = { Value = defaultPrinter },
             PaperSize = { Value = "A4" },
             ColorMode = { Value = (int)ColorModes.Auto },
@@ -46,6 +41,6 @@ public static class MacPrintInitialization
 
         vm.PrintPreview.PrintSettings.Value = currentPrintSettings;
 
-        Dispatcher.UIThread.InvokeAsync(printPreviewWindow.Initialize);
+        await Dispatcher.UIThread.InvokeAsync(() => printPreviewWindow.Initialize(path));
     }
 }

+ 22 - 22
src/PicView.Avalonia.MacOS/Views/PrintPreviewWindow.axaml.cs

@@ -22,6 +22,7 @@ namespace PicView.Avalonia.MacOS.Views;
 public partial class PrintPreviewWindow : Window
 {
     private const float PreviewDpi = 96f;
+    private object? _outputImage;
 
     public PrintPreviewWindow()
     {
@@ -40,7 +41,7 @@ public partial class PrintPreviewWindow : Window
         };
     }
 
-    public void Initialize()
+    public void Initialize(string filePath)
     {
         var vm = Dispatcher.UIThread.Invoke(() => DataContext as MainViewModel);
         
@@ -48,19 +49,17 @@ public partial class PrintPreviewWindow : Window
         {
             return;
         }
-
-        // Initial render
-        UpdatePreview(vm.PrintPreview);
         
         WindowFunctions.CenterWindowOnScreen(this);
 
+        vm.PrintPreview.PrintSettings.Value.ImagePath.Value = filePath;
         var ps = vm.PrintPreview.PrintSettings.Value;
 
         // Printer change
         ps.PrinterName
             .AsObservable()
             .DistinctUntilChanged()
-            .Subscribe(_ => UpdatePreview(vm.PrintPreview))
+            .SubscribeAwait(async (_, _) =>{ await UpdatePreviewAsync(vm.PrintPreview); })
             .AddTo(vm.PrintPreview.Disposables);
 
         // Any setting change triggers preview update
@@ -76,20 +75,20 @@ public partial class PrintPreviewWindow : Window
                 (orientation, top, bottom, left, right, scale, color, paper)
                     => (orientation, top, bottom, left, right, scale, color, paper))
             .ThrottleLast(TimeSpan.FromMilliseconds(100))
-            .Subscribe(_ => UpdatePreview(vm.PrintPreview))
+            .SubscribeAwait(async (_, _) =>{ await UpdatePreviewAsync(vm.PrintPreview); })
             .AddTo(vm.PrintPreview.Disposables);
     }
 
     // -----------------------------------------------------------
-    //   Preview rendering (uses same layout as print)
+    //   Preview rendering 
     // -----------------------------------------------------------
 
-    private void UpdatePreview(PrintPreviewViewModel vm)
+    private async ValueTask UpdatePreviewAsync(PrintPreviewViewModel vm)
     {
         var settings = vm.PrintSettings.Value;
-        var mainVm = Dispatcher.UIThread.Invoke(() => DataContext as MainViewModel);
-        var avaloniaBmp = mainVm.PicViewer?.ImageSource.Value as Bitmap;
-        
+        var mainVm= Dispatcher.UIThread.Invoke(() => DataContext as MainViewModel);
+        await using var fs = File.OpenRead(settings.ImagePath.Value);
+        var avaloniaBmp = new Bitmap(fs);
         
         // Grayscale if needed
         if (settings.ColorMode.Value == (int)ColorModes.BlackAndWhite)
@@ -117,8 +116,8 @@ public partial class PrintPreviewWindow : Window
         catch (Exception e)
         {
             // Fix null exception by loading from cache
-            DebugHelper.LogDebug(nameof(PrintPreviewView), nameof(UpdatePreview), e);
-            var cached = NavigationManager.GetPreLoadValueAsync(mainVm.PicViewer.FileInfo.Value).Result;
+            DebugHelper.LogDebug(nameof(PrintPreviewView), nameof(UpdatePreviewAsync), e);
+            var cached = await NavigationManager.GetPreLoadValueAsync(mainVm.PicViewer.FileInfo.Value);
             printLayout = PrintCore.ComputeLayout(
                 paper.WidthMm,
                 paper.HeightMm,
@@ -133,7 +132,7 @@ public partial class PrintPreviewWindow : Window
         var rtb = new RenderTargetBitmap(
             new PixelSize((int)layout.PageWidthPx, (int)layout.PageHeightPx));
         
-        Dispatcher.UIThread.Invoke(() =>
+        await Dispatcher.UIThread.InvokeAsync(() =>
         {
             using var ctx = rtb.CreateDrawingContext();
             ctx.FillRectangle(Brushes.White, new Rect(0, 0, layout.PageWidthPx, layout.PageHeightPx));
@@ -162,27 +161,28 @@ public partial class PrintPreviewWindow : Window
         vm.PreviewImage.Value = rtb;
         vm.PageWidth.Value = layout.PageWidthPx;
         vm.PageHeight.Value = layout.PageHeightPx;
+        
+        _outputImage = avaloniaBmp;
     }
 
     // -----------------------------------------------------------
     //   Print command
     // -----------------------------------------------------------
 
-    public async Task RunPrintAsync(MainViewModel vm)
+    public async ValueTask RunPrintAsync(MainViewModel vm)
     {
-        if (vm.PrintPreview == null) return;
-        var preview = vm.PrintPreview;
-        var settings = preview.PrintSettings.Value!;
-        if (DataContext is not MainViewModel mainVm) return;
-
-        if (mainVm.PicViewer?.ImageSource.Value is not Bitmap avaloniaBmp)
+        if (vm.PrintPreview == null)
+        {
             return;
+        }
+        var preview = vm.PrintPreview;
+        var settings = preview.PrintSettings.Value;
 
         preview.IsProcessing.Value = true;
 
         try
         {
-            await Task.Run(() => MacPrintEngine.RunPrintJob(settings, avaloniaBmp));
+            await Task.Run(() => MacPrintEngine.RunPrintJob(settings, _outputImage as Bitmap));
             await Dispatcher.UIThread.InvokeAsync(Close);
         }
         catch (Exception ex)

+ 1 - 3
src/PicView.Avalonia.MacOS/WindowImpl/WindowInitializer.cs

@@ -433,8 +433,6 @@ public class WindowInitializer : IPlatformSpecificUpdate
             {
                 vm.PrintPreview = new PrintPreviewViewModel();
 
-                // TODO: Move this initialization to its own dedicated class
-
                 _printPreviewWindow = new PrintPreviewWindow
                 {
                     DataContext = vm,
@@ -443,7 +441,7 @@ public class WindowInitializer : IPlatformSpecificUpdate
 
                 vm.PrintPreview.PrintCommand.SubscribeAwait(async (_, _) =>
                     {
-                        await _printPreviewWindow?.RunPrintAsync(vm);
+                        await _printPreviewWindow.RunPrintAsync(vm);
                     })
                     .AddTo(vm.PrintPreview.Disposables);
 

+ 17 - 8
src/PicView.Avalonia/FileSystem/FileManager.cs

@@ -1,4 +1,5 @@
-using Avalonia.Threading;
+using System.Runtime.InteropServices;
+using Avalonia.Threading;
 using PicView.Avalonia.ImageHandling;
 using PicView.Avalonia.Interfaces;
 using PicView.Avalonia.UI;
@@ -91,16 +92,24 @@ public static class FileManager
         try
         {
             vm.MainWindow.IsLoadingIndicatorShown.Value = true;
-            var file = await ImageFormatConverter.ConvertToCommonSupportedFormatAsync(path, vm)
-                .ConfigureAwait(false);
-
-            if (string.IsNullOrWhiteSpace(file))
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
             {
-                TooltipHelper.ShowTooltipMessage(TranslationManager.Translation.UnexpectedError);
-                return;
+                await Task.Run(() => vm.PlatformService.Print(path));
             }
+            else
+            {
+                // TODO: Refactor this for Windows
+                var file = await ImageFormatConverter.ConvertToCommonSupportedFormatAsync(path, vm)
+                    .ConfigureAwait(false);
 
-            await Task.Run(() => vm.PlatformService.Print(file));
+                if (string.IsNullOrWhiteSpace(file))
+                {
+                    TooltipHelper.ShowTooltipMessage(TranslationManager.Translation.UnexpectedError);
+                    return;
+                }
+
+                await Task.Run(() => vm.PlatformService.Print(file));
+            }
         }
         catch (Exception ex)
         {

+ 0 - 1
src/PicView.Avalonia/Views/Gallery/GalleryItem.axaml.cs

@@ -14,7 +14,6 @@ public partial class GalleryItem : UserControl
         InitializeComponent();
         if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
         {
-            PrintItem.IsVisible = false;
             CopyFileMenuItem.IsVisible = false;
         }
         GalleryContextMenu.Opened += delegate

+ 0 - 1
src/PicView.Avalonia/Views/Main/MainView.axaml.cs

@@ -29,7 +29,6 @@ public partial class MainView : UserControl
         if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
         {
             // TODO: Add macOS support
-            PrintMenuItem.IsVisible = false;
             CopyFileMenuItem.IsVisible = false;
             
             // Move alt hover to left side on macOS and switch button order