Browse Source

Print Preview / Settings / Window Maximized Overflow (#255)

* Update EditableTitlebar.axaml.cs

Right click Titlebar with no image loaded throws NullReferenceException

* Added Print Preview Feature

In multi-user Remote Desktop environments, the Windows Desktop Experience feature is unavailable preventing access to the built-in "Print Pictures" dialog when using the 'print' process verb. As a result, printing defaults directly to the user's default printer without allowing printer selection.

Added Enhanced printing functionality by adding print preview with support for selecting printers and print properties.

- Added Print Preview Window
- Added PrintEngine core class for unified print and preview layout handling
- Implemented shared ComputeLayout logic for consistent scaling and margins
- Integrated async RunPrintAsync with UI feedback
- Added grayscale conversion and Avalonia to GDI bitmap rendering
- Ensured 1:1 accuracy between on-screen preview and physical/PDF output

* Added Global Settings Config File

Added support for a GlobalSettings.json file in ApplicationDirectory/Config.
This file can define any settings from UserSettings.json and enforces them as global overrides at startup, regardless of values in the local or user profile UserSettings.json.

* Added Show SetAsWallpaper Setting Option

Added option in the UserSettings.json to be able to toggle the visibility of the SetAsWallpaper Menu buttons, preventing users being able to change the desktop wallpaper.

* Fixed Window Maximized Overflow

When using AcrylicBlur and the Window was maximized with Auto-fit Window turned off, Avalonia continued extending into that region instead of clipping to the screen’s working area, causing the content to overflow past the screen edges.

Setting ExtendClientAreaToDecorationsHint and SystemDecorations only while maximized allowed it to reapply its normal clipping and square-corner mask, fixing the overflow.

- Set window properties SystemDecorations and ExtenClientAreatoDecorationsHint when the window is maximized
- Removed SetMargin workaround

Aditional Changes
- Adjusted bottom bar drag region to avoid overlapping the settings button
- Adjusted titlebar layout so the window title is centered horizontally

* Fix incorrect image disposal at startup and fix printing shortcut not working properly.

Refine file handling in `FunctionsMapper` and improve eviction logic in `Preloader`

- Fixed `null` handling for `CurrentValue?.FullName` in multiple `FunctionsMapper` methods (`Print`, `OpenWith`, `OpenInExplorer`, etc.).
- Updated `Preloader` to conditionally invoke `ImageDisposalHelper` only on successful addition (`TryAdd` eviction handling).
- Removed unnecessary validation in `FileManager.Print`.
- Corrected eviction logic in `EvictingDictionary` (`_dictionary.Count > _maxSize`).

* Alphabetize languages

* Link `PrintPreviewView.axaml.cs` to `PrintPreviewView.axaml` in project file.

* Update Danish translation: Change "Skala" to "Skalering" in `da.json`.

* Fix titlebar not properly resizing at lower widths.

---------

Co-authored-by: Ruben <[email protected]>
mghe01 1 week ago
parent
commit
ac33b4d5fc
50 changed files with 1654 additions and 73 deletions
  1. 2 1
      src/PicView.Avalonia.MacOS/Views/MacMainWindow.axaml
  2. 4 1
      src/PicView.Avalonia.Win32/App.axaml.cs
  3. 371 0
      src/PicView.Avalonia.Win32/Printing/PrintEngine.cs
  4. 3 2
      src/PicView.Avalonia.Win32/Views/EffectsWindow.axaml
  5. 94 0
      src/PicView.Avalonia.Win32/Views/PrintPreviewWindow.axaml
  6. 233 0
      src/PicView.Avalonia.Win32/Views/PrintPreviewWindow.axaml.cs
  7. 7 0
      src/PicView.Avalonia.Win32/Views/WinMainWindow.axaml
  8. 1 2
      src/PicView.Avalonia.Win32/Views/WinTitleBar.axaml
  9. 0 25
      src/PicView.Avalonia.Win32/WindowImpl/Win32Window.cs
  10. 96 1
      src/PicView.Avalonia.Win32/WindowImpl/WindowInitializer.cs
  11. 24 0
      src/PicView.Avalonia/Converters/BoolToThicknessConverter.cs
  12. 3 0
      src/PicView.Avalonia/PicView.Avalonia.csproj
  13. 1 0
      src/PicView.Avalonia/ViewModels/MainViewModel.cs
  14. 12 6
      src/PicView.Avalonia/Views/Gallery/GalleryItem.axaml
  15. 3 2
      src/PicView.Avalonia/Views/Main/EffectsView.axaml
  16. 12 5
      src/PicView.Avalonia/Views/Main/ImageInfoView.axaml
  17. 3 2
      src/PicView.Avalonia/Views/Main/MainView.axaml
  18. 283 0
      src/PicView.Avalonia/Views/Main/PrintPreviewView.axaml
  19. 40 0
      src/PicView.Avalonia/Views/Main/PrintPreviewView.axaml.cs
  20. 6 4
      src/PicView.Avalonia/Views/UC/BottomBar.axaml
  21. 1 2
      src/PicView.Avalonia/Views/UC/TitleTextBox.axaml
  22. 3 0
      src/PicView.Avalonia/Wallpaper/WallpaperManager.cs
  23. 10 0
      src/PicView.Core/Config/AppSettings.cs
  24. 8 0
      src/PicView.Core/Config/Languages/da.json
  25. 8 0
      src/PicView.Core/Config/Languages/de.json
  26. 10 1
      src/PicView.Core/Config/Languages/en.json
  27. 8 0
      src/PicView.Core/Config/Languages/es.json
  28. 8 0
      src/PicView.Core/Config/Languages/fr.json
  29. 8 0
      src/PicView.Core/Config/Languages/he.json
  30. 8 0
      src/PicView.Core/Config/Languages/hu.json
  31. 8 0
      src/PicView.Core/Config/Languages/it.json
  32. 8 0
      src/PicView.Core/Config/Languages/ja.json
  33. 8 0
      src/PicView.Core/Config/Languages/ko.json
  34. 8 0
      src/PicView.Core/Config/Languages/nl.json
  35. 8 0
      src/PicView.Core/Config/Languages/pl.json
  36. 8 0
      src/PicView.Core/Config/Languages/pt-br.json
  37. 8 0
      src/PicView.Core/Config/Languages/ro.json
  38. 8 0
      src/PicView.Core/Config/Languages/ru.json
  39. 8 0
      src/PicView.Core/Config/Languages/sr.json
  40. 8 0
      src/PicView.Core/Config/Languages/sv.json
  41. 8 0
      src/PicView.Core/Config/Languages/tr.json
  42. 8 0
      src/PicView.Core/Config/Languages/zh-CN.json
  43. 8 0
      src/PicView.Core/Config/Languages/zh-TW.json
  44. 6 0
      src/PicView.Core/Config/SettingsConfiguration.cs
  45. 93 16
      src/PicView.Core/Config/SettingsManager.cs
  46. 8 0
      src/PicView.Core/Localization/LanguageModel.cs
  47. 52 0
      src/PicView.Core/Printing/PrintSettings.cs
  48. 4 2
      src/PicView.Core/ViewModels/GlobalSettingsViewModel.cs
  49. 93 0
      src/PicView.Core/ViewModels/PrintPreviewViewModel.cs
  50. 24 1
      src/PicView.Core/ViewModels/TranslationViewModel.cs

+ 2 - 1
src/PicView.Avalonia.MacOS/Views/MacMainWindow.axaml

@@ -294,7 +294,8 @@
                         Header="{CompiledBinding Translation.SetAsWallpaper.Value,
                                                  Mode=OneWay}"
                         IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                    Converter={x:Static ObjectConverters.IsNotNull}}" />
+                                                    Converter={x:Static ObjectConverters.IsNotNull}}"
+                        IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}" />
 
                     <NativeMenuItemSeparator />
 

+ 4 - 1
src/PicView.Avalonia.Win32/App.axaml.cs

@@ -160,7 +160,10 @@ public class App : Application, IPlatformSpecificService, IPlatformWindowService
 
     public void Print(string path)
     {
-        ProcessHelper.Print(path);
+        if (Settings.UIProperties.ShowPrintPreview)
+            _windowInitializer?.ShowPrintPreviewWindow(_vm);
+        else
+            ProcessHelper.Print(path);
     }
 
     public async Task SetAsWallpaper(string path, int wallpaperStyle)

+ 371 - 0
src/PicView.Avalonia.Win32/Printing/PrintEngine.cs

@@ -0,0 +1,371 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Threading;
+using PicView.Avalonia.ViewModels;
+using PicView.Core.ViewModels;
+using R3;
+using System.Drawing.Printing;
+using System.Runtime.InteropServices;
+using Avalonia.Platform;
+using PicView.Avalonia.Printing;
+
+namespace PicView.Avalonia.Win32.Printing
+{
+    public static class PrintEngine
+    {
+        private const float PreviewDpi = 96f;
+        private const double MmPerInch = 25.4;
+
+        // Entry point used by UI layer
+        public static void RunPrintJob(PrintSettings settings, Bitmap avaloniaBmp)
+        {
+            if (settings.ColorMode.Value == (int)ColorModes.BlackAndWhite)
+                avaloniaBmp = ToGrayScale(avaloniaBmp, PreviewDpi);
+
+            using var gdiBitmap = BuildPrintableBitmap(settings, avaloniaBmp);
+            Print(settings, gdiBitmap);
+        }
+
+
+        public static System.Drawing.Bitmap BuildPrintableBitmap(PrintSettings settings, Bitmap avaloniaBmp)
+        {
+            var paperInfo = ResolvePaper(settings.PrinterName.Value, settings.PaperSize.Value, (settings.Orientation.Value == (int)Orientations.Landscape));
+            if (paperInfo is null)
+                throw new InvalidOperationException("Invalid paper configuration.");
+
+            int paperWidthPx = MmToPx(paperInfo.WidthMm, PreviewDpi);
+            int paperHeightPx = MmToPx(paperInfo.HeightMm, PreviewDpi);
+
+            var gdiBmp = new System.Drawing.Bitmap(paperWidthPx, paperHeightPx, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
+
+            using (var g = System.Drawing.Graphics.FromImage(gdiBmp))
+            {
+                g.Clear(System.Drawing.Color.White);
+                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
+                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
+
+                var contentRect = GetContentRect(settings, paperWidthPx, paperHeightPx);
+                using var src = AvaloniaToGdi(avaloniaBmp);
+                var destRect = ComputeDestRect(settings, src, contentRect);
+
+                g.DrawImage(src, destRect);
+            }
+
+            return gdiBmp;
+        }
+
+        public static void Print(PrintSettings settings, System.Drawing.Bitmap image)
+        {
+            using var pd = new System.Drawing.Printing.PrintDocument
+            {
+                PrinterSettings = new System.Drawing.Printing.PrinterSettings
+                {
+                    PrinterName = settings.PrinterName.Value ?? string.Empty,
+                    Copies = (short)settings.Copies.Value
+                },
+                PrintController = new StandardPrintController() // no dialog
+            };
+
+            var paperInfo = ResolvePaper(settings.PrinterName.Value, settings.PaperSize.Value, false);
+            if (paperInfo?.DriverPaper is PaperSize paper)
+                pd.DefaultPageSettings.PaperSize = paper;
+
+            pd.DefaultPageSettings.Landscape = settings.Orientation.Value == (int)Orientations.Landscape;
+            pd.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
+            pd.DefaultPageSettings.Color = settings.ColorMode.Value != (int)ColorModes.BlackAndWhite;
+
+            pd.PrintPage += (_, e) =>
+            {
+                e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
+                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
+                e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
+
+                float dpiX = e.Graphics.DpiX;
+                float dpiY = e.Graphics.DpiY;
+
+                var page = e.PageBounds;                // 1/100 inch units
+                const double mmToHi = 100.0 / 25.4;     // 1 mm = 3.937 hundredths inch
+
+                // margins in hundredths of inch
+                float ml = (float)(settings.MarginLeft.Value * mmToHi);
+                float mr = (float)(settings.MarginRight.Value * mmToHi);
+                float mt = (float)(settings.MarginTop.Value * mmToHi);
+                float mb = (float)(settings.MarginBottom.Value * mmToHi);
+
+                // drawable content area (full page coordinates)
+                var contentRect = new System.Drawing.RectangleF(0, 0, page.Width, page.Height);
+
+                var img = image;
+                float imgW = img.Width * 100f / dpiX;
+                float imgH = img.Height * 100f / dpiY;
+
+                double sx = contentRect.Width / imgW;
+                double sy = contentRect.Height / imgH;
+                double s = settings.ScaleMode.Value switch
+                {
+                    (int)ScaleModes.Fill => Math.Max(sx, sy),
+                    (int)ScaleModes.Fit => Math.Min(sx, sy),
+                    (int)ScaleModes.Stretch => 0,
+                    _ => 1.0
+                };
+
+                System.Drawing.RectangleF destRect =
+                    settings.ScaleMode.Value == (int)ScaleModes.Stretch
+                    ? contentRect
+                    : new System.Drawing.RectangleF(
+                        (float)((contentRect.Width - imgW * s) / 2),
+                        (float)((contentRect.Height - imgH * s) / 2),
+                        (float)(imgW * s),
+                        (float)(imgH * s));
+
+                e.Graphics.DrawImage(img, destRect);
+                e.HasMorePages = false;
+            };
+
+
+
+            pd.Print();
+        }
+
+
+        // -----------------------------------------------------------
+        //   Utility Methods
+        // -----------------------------------------------------------
+
+        private static System.Drawing.Rectangle GetContentRect(PrintSettings settings, int pageW, int pageH)
+        {
+            int ml = MmToPx(settings.MarginLeft.Value, PreviewDpi);
+            int mr = MmToPx(settings.MarginRight.Value, PreviewDpi);
+            int mt = MmToPx(settings.MarginTop.Value, PreviewDpi);
+            int mb = MmToPx(settings.MarginBottom.Value, PreviewDpi);
+
+            return new System.Drawing.Rectangle(
+                ml, mt,
+                pageW - (ml + mr),
+                pageH - (mt + mb));
+        }
+
+        private static System.Drawing.Rectangle ComputeDestRect(PrintSettings settings, System.Drawing.Bitmap src, System.Drawing.Rectangle content)
+        {
+            double sx = (double)content.Width / src.Width;
+            double sy = (double)content.Height / src.Height;
+
+            double scale = settings.ScaleMode.Value switch
+            {
+                (int)ScaleModes.Fill => Math.Max(sx, sy),
+                (int)ScaleModes.Fit => Math.Min(sx, sy),
+                (int)ScaleModes.Stretch => 0,
+                _ => 1.0
+            };
+
+            if (settings.ScaleMode.Value == (int)ScaleModes.Stretch)
+                return content;
+
+            if (settings.ScaleMode.Value == (int)ScaleModes.Center)
+            {
+                int dx = content.X + (content.Width - src.Width) / 2;
+                int dy = content.Y + (content.Height - src.Height) / 2;
+                return new System.Drawing.Rectangle(dx, dy, src.Width, src.Height);
+            }
+
+            int dw = (int)Math.Round(src.Width * scale);
+            int dh = (int)Math.Round(src.Height * scale);
+            int x = content.X + (content.Width - dw) / 2;
+            int y = content.Y + (content.Height - dh) / 2;
+            return new System.Drawing.Rectangle(x, y, dw, dh);
+        }
+
+        private static int MmToPx(double mm, float dpi) => (int)Math.Round(mm / MmPerInch * dpi);
+        private static int MmToHundredths(double mm) => (int)Math.Round(mm * 100.0 / MmPerInch);
+        private static int HundredthsToMm(double hdth) => (int)Math.Round(hdth / 100.0 * MmPerInch);
+
+        public static PaperInfo? ResolvePaper(string printerName, string requestedName, bool landscape)
+        {
+            try
+            {
+                var ps = new PrinterSettings { PrinterName = printerName };
+                foreach (PaperSize p in ps.PaperSizes)
+                {
+                    if (requestedName.StartsWith(p.PaperName, StringComparison.OrdinalIgnoreCase) ||
+                        p.PaperName.StartsWith(requestedName, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return new PaperInfo(p.PaperName,
+                                HundredthsToMm((landscape ? p.Height : p.Width)),
+                                HundredthsToMm((landscape ? p.Width : p.Height)),
+                                p);
+                    }
+                }
+            }
+            catch { }
+            return null;
+        }
+
+        public static IEnumerable<string> GetPaperSizes(string printerName)
+        {
+            var ps = new PrinterSettings { PrinterName = printerName };
+            return ps.PaperSizes.Cast<PaperSize>().Select(p => p.PaperName);
+        }
+
+        private static System.Drawing.Bitmap AvaloniaToGdi(Bitmap avaloniaBmp)
+        {
+            int width = avaloniaBmp.PixelSize.Width;
+            int height = avaloniaBmp.PixelSize.Height;
+            int stride = width * 4;
+            int bufferSize = stride * height;
+
+            IntPtr bufferPtr = Marshal.AllocHGlobal(bufferSize);
+            try
+            {
+                avaloniaBmp.CopyPixels(new PixelRect(0, 0, width, height), bufferPtr, bufferSize, stride);
+
+                var data = new byte[bufferSize];
+                Marshal.Copy(bufferPtr, data, 0, bufferSize);
+
+                var bmp = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+                var bmpData = bmp.LockBits(
+                    new System.Drawing.Rectangle(0, 0, width, height),
+                    System.Drawing.Imaging.ImageLockMode.WriteOnly,
+                    System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+                Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
+                bmp.UnlockBits(bmpData);
+                return bmp;
+            }
+            finally
+            {
+                if (bufferPtr != IntPtr.Zero)
+                    Marshal.FreeHGlobal(bufferPtr);
+            }
+        }
+
+        public static Bitmap ToGrayScale(Bitmap src, float dpi)
+        {
+            int width = src.PixelSize.Width;
+            int height = src.PixelSize.Height;
+            int stride = width * 4;
+            int bufferSize = height * stride;
+
+            IntPtr pixelBuffer = IntPtr.Zero;
+
+            try
+            {
+                pixelBuffer = Marshal.AllocHGlobal(bufferSize);
+                var rect = new PixelRect(0, 0, width, height);
+                src.CopyPixels(rect, pixelBuffer, bufferSize, stride);
+
+                var managed = new byte[bufferSize];
+                Marshal.Copy(pixelBuffer, managed, 0, bufferSize);
+
+                for (int i = 0; i < managed.Length; i += 4)
+                {
+                    byte gray = (byte)(0.2126 * managed[i + 2] +
+                                       0.7152 * managed[i + 1] +
+                                       0.0722 * managed[i + 0]);
+                    managed[i + 0] = gray;
+                    managed[i + 1] = gray;
+                    managed[i + 2] = gray;
+                }
+
+                var dst = new WriteableBitmap(
+                    src.PixelSize,
+                    new Vector(dpi, dpi),
+                    PixelFormat.Bgra8888,
+                    AlphaFormat.Premul);
+
+                using (var fb = dst.Lock())
+                    Marshal.Copy(managed, 0, fb.Address, managed.Length);
+
+                return dst;
+            }
+            finally
+            {
+                if (pixelBuffer != IntPtr.Zero)
+                    Marshal.FreeHGlobal(pixelBuffer);
+            }
+        }
+
+
+
+
+        public static PrintLayout ComputeLayout(double pageWidthMm, double pageHeightMm, PrintSettings settings, double imageWidthPx, double imageHeightPx, double dpi)
+        {
+            double mmToPx = dpi / 25.4;
+            double pageWpx = pageWidthMm * mmToPx;
+            double pageHpx = pageHeightMm * mmToPx;
+
+            // Margins
+            double ml = settings.MarginLeft.Value * mmToPx;
+            double mr = settings.MarginRight.Value * mmToPx;
+            double mt = settings.MarginTop.Value * mmToPx;
+            double mb = settings.MarginBottom.Value * mmToPx;
+
+            double contentW = pageWpx - (ml + mr);
+            double contentH = pageHpx - (mt + mb);
+
+            // Scale
+            double sX = contentW / imageWidthPx;
+            double sY = contentH / imageHeightPx;
+            double s = settings.ScaleMode.Value switch
+            {
+                (int)ScaleModes.Fill => Math.Max(sX, sY),
+                (int)ScaleModes.Stretch => 1.0,
+                _ => Math.Min(sX, sY)
+            };
+
+            double drawW = (settings.ScaleMode.Value == (int)ScaleModes.Stretch)
+                ? contentW : imageWidthPx * s;
+            double drawH = (settings.ScaleMode.Value == (int)ScaleModes.Stretch)
+                ? contentH : imageHeightPx * s;
+            double dx = ml + (contentW - drawW) / 2;
+            double dy = mt + (contentH - drawH) / 2;
+
+            return new PrintLayout(dx, dy, drawW, drawH, pageWpx, pageHpx, ml, mt, contentW, contentH);
+        }
+
+
+
+        public readonly struct PrintLayout
+        {
+            public readonly double DrawX;
+            public readonly double DrawY;
+            public readonly double DrawWidth;
+            public readonly double DrawHeight;
+            public readonly double PageWidthPx;
+            public readonly double PageHeightPx;
+            public readonly double ContentX;
+            public readonly double ContentY;
+            public readonly double ContentWidth;
+            public readonly double ContentHeight;
+
+            public PrintLayout(double dx, double dy, double dw, double dh, double pw, double ph, double cx, double cy, double cw, double ch)
+            {
+                DrawX = dx; DrawY = dy; DrawWidth = dw; DrawHeight = dh;
+                PageWidthPx = pw; PageHeightPx = ph;
+                ContentX = cx; ContentY = cy; ContentWidth = cw; ContentHeight = ch;
+            }
+        }
+
+
+        public class PaperInfo
+        {
+            public string Name { get; }
+            public double WidthMm { get; }
+            public double HeightMm { get; }
+            public PaperSize? DriverPaper { get; }
+            public PaperInfo(string name, double widthMm, double heightMm, PaperSize? driverPaper)
+            {
+                Name = name;
+                WidthMm = widthMm;
+                HeightMm = heightMm;
+                DriverPaper = driverPaper;
+            }
+        }
+    }
+}

+ 3 - 2
src/PicView.Avalonia.Win32/Views/EffectsWindow.axaml

@@ -118,7 +118,8 @@
                                 CommandParameter="{CompiledBinding PicViewer.FileInfo.Value.FullName,
                                                                    FallbackValue=''}"
                                 Header="{CompiledBinding Translation.SetAsWallpaper.Value,
-                                                         Mode=OneWay}">
+                                                         Mode=OneWay}"
+                                IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                                 <MenuItem.Icon>
                                     <Path
                                         Data="{StaticResource PanoramaGeometry}"
@@ -128,7 +129,7 @@
                                         Width="13" />
                                 </MenuItem.Icon>
                             </MenuItem>
-                            <Separator />
+                            <Separator IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}" />
                             <MenuItem Header="{CompiledBinding Translation.ClearEffects.Value, Mode=OneWay}" x:Name="ClearEffectsItem">
                                 <MenuItem.Icon>
                                     <Image

+ 94 - 0
src/PicView.Avalonia.Win32/Views/PrintPreviewWindow.axaml

@@ -0,0 +1,94 @@
+<Window
+    BorderThickness="1"
+    CanResize="False"
+    CornerRadius="8"
+    SizeToContent="WidthAndHeight"
+    Title="Loading..."
+    x:Class="PicView.Avalonia.Win32.Views.PrintPreviewWindow"
+    x:DataType="viewModels:MainViewModel"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls;assembly=PicView.Avalonia"
+    xmlns:main="clr-namespace:PicView.Avalonia.Views.Main;assembly=PicView.Avalonia"
+    xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels;assembly=PicView.Avalonia"
+    xmlns:views="clr-namespace:PicView.Avalonia.Views;assembly=PicView.Avalonia"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+    <Border
+        BorderBrush="{DynamicResource WindowBorderColor}"
+        BorderThickness="1"
+        PointerPressed="MoveWindow"
+        x:Name="ParentBorder">
+        <StackPanel>
+
+            <DockPanel Height="28" LastChildFill="True">
+
+                <Border
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="0,0,1,0"
+                    DockPanel.Dock="Left"
+                    x:Name="IconBorder">
+                    <Image
+                        Height="25"
+                        Margin="7,1,7,1"
+                        Source="{StaticResource LogoImage}"
+                        Width="20" />
+                </Border>
+
+                <customControls:IconButton
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderThickness="0"
+                    Classes="hover"
+                    Click="Close"
+                    ClickMode="Release"
+                    Data="{StaticResource CloseGeometry}"
+                    DockPanel.Dock="Right"
+                    Foreground="{DynamicResource MainTextColor}"
+                    IconHeight="10"
+                    IconWidth="10"
+                    IsRepeatEnabled="False"
+                    Width="30"
+                    x:Name="CloseButton" />
+
+                <customControls:IconButton
+                    Background="{DynamicResource WindowButtonBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1,0,1,0"
+                    Classes="hover"
+                    Click="Minimize"
+                    Data="{StaticResource MinimizeGeometry}"
+                    DockPanel.Dock="Right"
+                    Foreground="{DynamicResource MainTextColor}"
+                    IconHeight="12"
+                    IconWidth="12"
+                    IsRepeatEnabled="False"
+                    Width="30"
+                    x:Name="MinimizeButton" />
+
+                <TextBlock
+                    Background="{DynamicResource WindowSecondaryBackgroundColor}"
+                    Classes="txt"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Height="28"
+                    LineHeight="28"
+                    Padding="30,0,0,0"
+                    Text="{CompiledBinding Translation.Print.Value, Mode=OneWay}"
+                    TextAlignment="Center"
+                    x:Name="TitleText" />
+            </DockPanel>
+
+            <Rectangle
+                Fill="{DynamicResource WindowBorderColor}"
+                Height="1"
+                x:Name="BorderRectangle" />
+
+			<main:PrintPreviewView                
+				Background="{DynamicResource WindowBackgroundColor}"
+                Focusable="True"
+                Margin="0"
+                Padding="10,2,5,10"
+                PointerPressed="MoveWindow"
+                x:Name="PrintPreviewView" />
+        </StackPanel>
+    </Border>
+</Window>

+ 233 - 0
src/PicView.Avalonia.Win32/Views/PrintPreviewWindow.axaml.cs

@@ -0,0 +1,233 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Threading;
+using PicView.Avalonia.ViewModels;
+using PicView.Core.ViewModels;
+using R3;
+using System.Drawing.Printing;
+using System.Runtime.InteropServices;
+using Avalonia.Platform;
+using PicView.Avalonia.Printing;
+using PicView.Avalonia.Win32.Printing;
+
+namespace PicView.Avalonia.Win32.Views;
+
+public partial class PrintPreviewWindow : Window
+{
+    private const float PreviewDpi = 96f;
+
+    public PrintPreviewWindow()
+    {
+        InitializeComponent();
+
+        // Glass/Transparent theme support
+        if (Settings.Theme.GlassTheme)
+        {
+            IconBorder.Background = Brushes.Transparent;
+            IconBorder.BorderThickness = new Thickness(0);
+            MinimizeButton.Background = Brushes.Transparent;
+            MinimizeButton.BorderThickness = new Thickness(0);
+            CloseButton.Background = Brushes.Transparent;
+            CloseButton.BorderThickness = new Thickness(0);
+            BorderRectangle.Height = 0;
+            TitleText.Background = Brushes.Transparent;
+
+            if (!Application.Current.TryGetResource("SecondaryTextColor",
+                    Application.Current.RequestedThemeVariant, out var textColor)) return;
+            if (textColor is not Color color) return;
+
+            var brush = new SolidColorBrush(color);
+            TitleText.Foreground = brush;
+            MinimizeButton.Foreground = brush;
+            CloseButton.Foreground = brush;
+        }
+    }
+
+    private void MoveWindow(object? sender, PointerPressedEventArgs e)
+    {
+        if (VisualRoot is Window hostWindow)
+            hostWindow.BeginMoveDrag(e);
+    }
+
+    private void Close(object? sender, RoutedEventArgs e) => Close();
+    private void Minimize(object? sender, RoutedEventArgs e) => WindowState = WindowState.Minimized;
+
+    protected override void OnLoaded(RoutedEventArgs e)
+    {
+        base.OnLoaded(e);
+
+        if (DataContext is not MainViewModel vm) return;
+        if (vm.PrintPreview == null) return;
+
+        var ps = vm.PrintPreview.PrintSettings.Value;
+
+        // Printer change
+        ps.PrinterName
+            .AsObservable()
+            .DistinctUntilChanged()
+            .Subscribe(_ => UpdatePrinter(vm.PrintPreview))
+            .AddTo(vm.PrintPreview._disposables);
+
+        // Any setting change triggers preview update
+        Observable.CombineLatest(
+                ps.Orientation.AsObservable(),
+                ps.MarginTop.AsObservable(),
+                ps.MarginBottom.AsObservable(),
+                ps.MarginLeft.AsObservable(),
+                ps.MarginRight.AsObservable(),
+                ps.ScaleMode.AsObservable(),
+                ps.ColorMode.AsObservable(),
+                ps.PaperSize.AsObservable(),
+                (orientation, top, bottom, left, right, scale, color, paper)
+                    => (orientation, top, bottom, left, right, scale, color, paper))
+            .ThrottleLast(TimeSpan.FromMilliseconds(100))
+            .Subscribe(_ => UpdatePreview(vm.PrintPreview))
+            .AddTo(vm.PrintPreview._disposables);
+
+        // Initial render
+        UpdatePrinter(vm.PrintPreview);
+        UpdatePreview(vm.PrintPreview);
+    }
+
+
+    // -----------------------------------------------------------
+    //   Printer setup
+    // -----------------------------------------------------------
+
+    public void UpdatePrinter(PrintPreviewViewModel vm)
+    {
+        var settings = vm.PrintSettings.Value;
+        if (settings == null) return;
+        if (string.IsNullOrWhiteSpace(settings.PrinterName.Value)) return;
+
+        try
+        {
+            var ps = new PrinterSettings { PrinterName = settings.PrinterName.Value };
+            var sizes = ps.PaperSizes.Cast<PaperSize>().Select(p => p.PaperName).ToList();
+
+            var currentPaper = settings.PaperSize.Value ?? string.Empty;
+            if (!sizes.Contains(currentPaper))
+            {
+                currentPaper =
+                    sizes.FirstOrDefault(p =>
+                        p.StartsWith(currentPaper, StringComparison.OrdinalIgnoreCase) ||
+                        currentPaper.StartsWith(p, StringComparison.OrdinalIgnoreCase))
+                    ?? sizes.FirstOrDefault()
+                    ?? string.Empty;
+            }
+
+            vm.PaperSizes.Value = new ObservableCollection<string>(sizes);
+            settings.PaperSize.Value = currentPaper;
+        }
+        catch (Exception ex)
+        {
+            Console.WriteLine($"[PrintPreview] Failed to reload paper sizes: {ex}");
+        }
+    }
+
+
+    // -----------------------------------------------------------
+    //   Preview rendering (uses same layout as print)
+    // -----------------------------------------------------------
+
+    private void UpdatePreview(PrintPreviewViewModel vm)
+    {
+        try
+        {
+            var settings = vm.PrintSettings.Value;
+            if (settings == null) return;
+            if (DataContext is not MainViewModel mainVm) return;
+            if (mainVm.PicViewer?.ImageSource.Value is not Bitmap avaloniaBmp) return;
+
+            // Grayscale if needed
+            if (settings.ColorMode.Value == (int)ColorModes.BlackAndWhite)
+            {
+                vm.GrayCache ??= PrintEngine.ToGrayScale(avaloniaBmp, PreviewDpi);
+                avaloniaBmp = (Bitmap)vm.GrayCache;
+            }
+            else vm.GrayCache = null;
+
+            // Resolve paper
+            var paperInfo = PrintEngine.ResolvePaper(settings.PrinterName.Value, settings.PaperSize.Value, (settings.Orientation.Value == (int)Orientations.Landscape));
+            if (paperInfo is null) return;
+
+            // Compute layout once
+            var layout = PrintEngine.ComputeLayout(
+                paperInfo.WidthMm, paperInfo.HeightMm, settings,
+                avaloniaBmp.PixelSize.Width,
+                avaloniaBmp.PixelSize.Height,
+                PreviewDpi);
+
+            var rtb = new RenderTargetBitmap(
+                new PixelSize((int)layout.PageWidthPx, (int)layout.PageHeightPx));
+
+            using (var ctx = rtb.CreateDrawingContext())
+            {
+                ctx.FillRectangle(Brushes.White, new Rect(0, 0, layout.PageWidthPx, layout.PageHeightPx));
+                ctx.DrawRectangle(null, new Pen(Brushes.LightGray, 1),
+                    new Rect(0.5, 0.5, layout.PageWidthPx - 1, layout.PageHeightPx - 1));
+
+                var destRect = new Rect(layout.DrawX, layout.DrawY, layout.DrawWidth, layout.DrawHeight);
+
+                var dashPen = new Pen(Brushes.Gray, 2)
+                {
+                    DashStyle = new DashStyle(new double[] { 4, 2 }, 0)
+                };
+                ctx.DrawRectangle(null, dashPen,
+                    new Rect(layout.ContentX, layout.ContentY, layout.ContentWidth, layout.ContentHeight));
+
+                ctx.DrawImage(avaloniaBmp,
+                    new Rect(0, 0, avaloniaBmp.PixelSize.Width, avaloniaBmp.PixelSize.Height),
+                    destRect);
+            }
+
+            if (vm.PreviewImage.Value is Bitmap old)
+                old.Dispose();
+
+            vm.PreviewImage.Value = rtb;
+            vm.PageWidth.Value = layout.PageWidthPx;
+            vm.PageHeight.Value = layout.PageHeightPx;
+        }
+        catch (Exception ex)
+        {
+            Console.WriteLine($"[PrintPreview] UpdatePreview failed: {ex}");
+        }
+    }
+
+
+    // -----------------------------------------------------------
+    //   Print command
+    // -----------------------------------------------------------
+
+    public async Task 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) return;
+
+        preview.IsProcessing.Value = true;
+
+        try
+        {
+            await Task.Run(() => PrintEngine.RunPrintJob(settings, avaloniaBmp));
+            await Dispatcher.UIThread.InvokeAsync(Close);
+        }
+        catch (Exception ex)
+        {
+            Console.WriteLine($"[PrintPreview] RunPrintAsync error: {ex}");
+        }
+        finally
+        {
+            preview.IsProcessing.Value = false;
+        }
+    }
+}

+ 7 - 0
src/PicView.Avalonia.Win32/Views/WinMainWindow.axaml

@@ -17,6 +17,13 @@
     xmlns:views1="clr-namespace:PicView.Avalonia.Win32.Views"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
+	<Window.Styles>
+        <Style Selector="Window[WindowState=Maximized]">
+            <Setter Property="SystemDecorations" Value="None" />
+            <Setter Property="ExtendClientAreaToDecorationsHint" Value="False" />
+        </Style>
+    </Window.Styles>
+    
     <Border BorderBrush="{DynamicResource WindowBorderColor}" BorderThickness="1">
         <DockPanel LastChildFill="True">
             <views1:WinTitleBar DockPanel.Dock="Top" x:Name="Titlebar" />

+ 1 - 2
src/PicView.Avalonia.Win32/Views/WinTitleBar.axaml

@@ -234,8 +234,7 @@
                                 <Image.Source>
                                     <DrawingImage>
                                         <DrawingGroup>
-                                            <GeometryDrawing
-                                                Geometry="F1 M12 6L6 6Q5.90175 6 5.80397 6.00963Q5.70618 6.01926 5.60982 6.03843Q5.51345 6.0576 5.41943 6.08612Q5.32541 6.11464 5.23463 6.15224Q5.14386 6.18984 5.05721 6.23616Q4.97055 6.28247 4.88886 6.33706Q4.80716 6.39165 4.73121 6.45398Q4.65526 6.51631 4.58579 6.58579Q4.51631 6.65526 4.45398 6.73121Q4.39165 6.80717 4.33706 6.88886Q4.28247 6.97056 4.23616 7.05721Q4.18984 7.14386 4.15224 7.23463Q4.11464 7.32541 4.08612 7.41943Q4.0576 7.51345 4.03843 7.60982Q4.01926 7.70619 4.00963 7.80397Q4 7.90175 4 8L4 18Q4 18.0983 4.00963 18.196Q4.01926 18.2938 4.03843 18.3902Q4.0576 18.4865 4.08612 18.5806Q4.11464 18.6746 4.15224 18.7654Q4.18984 18.8561 4.23616 18.9428Q4.28247 19.0294 4.33706 19.1111Q4.39165 19.1928 4.45398 19.2688Q4.51631 19.3447 4.58579 19.4142Q4.65526 19.4837 4.73121 19.546Q4.80716 19.6083 4.88886 19.6629Q4.97055 19.7175 5.05721 19.7638Q5.14386 19.8102 5.23463 19.8478Q5.32541 19.8854 5.41943 19.9139Q5.51345 19.9424 5.60982 19.9616Q5.70618 19.9807 5.80397 19.9904Q5.90175 20 6 20L16 20Q16.0983 20 16.196 19.9904Q16.2938 19.9807 16.3902 19.9616Q16.4865 19.9424 16.5806 19.9139Q16.6746 19.8854 16.7654 19.8478Q16.8561 19.8102 16.9428 19.7638Q17.0294 19.7175 17.1111 19.6629Q17.1928 19.6084 17.2688 19.546Q17.3447 19.4837 17.4142 19.4142Q17.4837 19.3447 17.546 19.2688Q17.6084 19.1928 17.6629 19.1111Q17.7175 19.0294 17.7638 18.9428Q17.8102 18.8561 17.8478 18.7654Q17.8854 18.6746 17.9139 18.5806Q17.9424 18.4865 17.9616 18.3902Q17.9807 18.2938 17.9904 18.196Q18 18.0983 18 18L18 12">
+                                            <GeometryDrawing Geometry="F1 M12 6L6 6Q5.90175 6 5.80397 6.00963Q5.70618 6.01926 5.60982 6.03843Q5.51345 6.0576 5.41943 6.08612Q5.32541 6.11464 5.23463 6.15224Q5.14386 6.18984 5.05721 6.23616Q4.97055 6.28247 4.88886 6.33706Q4.80716 6.39165 4.73121 6.45398Q4.65526 6.51631 4.58579 6.58579Q4.51631 6.65526 4.45398 6.73121Q4.39165 6.80717 4.33706 6.88886Q4.28247 6.97056 4.23616 7.05721Q4.18984 7.14386 4.15224 7.23463Q4.11464 7.32541 4.08612 7.41943Q4.0576 7.51345 4.03843 7.60982Q4.01926 7.70619 4.00963 7.80397Q4 7.90175 4 8L4 18Q4 18.0983 4.00963 18.196Q4.01926 18.2938 4.03843 18.3902Q4.0576 18.4865 4.08612 18.5806Q4.11464 18.6746 4.15224 18.7654Q4.18984 18.8561 4.23616 18.9428Q4.28247 19.0294 4.33706 19.1111Q4.39165 19.1928 4.45398 19.2688Q4.51631 19.3447 4.58579 19.4142Q4.65526 19.4837 4.73121 19.546Q4.80716 19.6083 4.88886 19.6629Q4.97055 19.7175 5.05721 19.7638Q5.14386 19.8102 5.23463 19.8478Q5.32541 19.8854 5.41943 19.9139Q5.51345 19.9424 5.60982 19.9616Q5.70618 19.9807 5.80397 19.9904Q5.90175 20 6 20L16 20Q16.0983 20 16.196 19.9904Q16.2938 19.9807 16.3902 19.9616Q16.4865 19.9424 16.5806 19.9139Q16.6746 19.8854 16.7654 19.8478Q16.8561 19.8102 16.9428 19.7638Q17.0294 19.7175 17.1111 19.6629Q17.1928 19.6084 17.2688 19.546Q17.3447 19.4837 17.4142 19.4142Q17.4837 19.3447 17.546 19.2688Q17.6084 19.1928 17.6629 19.1111Q17.7175 19.0294 17.7638 18.9428Q17.8102 18.8561 17.8478 18.7654Q17.8854 18.6746 17.9139 18.5806Q17.9424 18.4865 17.9616 18.3902Q17.9807 18.2938 17.9904 18.196Q18 18.0983 18 18L18 12">
                                                 <GeometryDrawing.Pen>
                                                     <Pen
                                                         Brush="{DynamicResource MainTextColor}"

+ 0 - 25
src/PicView.Avalonia.Win32/WindowImpl/Win32Window.cs

@@ -75,7 +75,6 @@ public static class Win32Window
             window.WindowState = WindowState.Maximized;
             Settings.WindowProperties.Maximized = true;
             WindowResizing.SetSize(vm);
-            SetMargin(vm, window);
         });
 
         vm.MainWindow.IsMaximized.Value = true;
@@ -99,7 +98,6 @@ public static class Win32Window
         Settings.WindowProperties.Fullscreen = false;
 
         // Update UI state
-        SetMargin(vm, window);
         vm.MainWindow.IsMaximized.Value = false;
         vm.MainWindow.IsFullscreen.Value = false;
 
@@ -213,28 +211,5 @@ public static class Win32Window
         vm.MainWindow.IsUIShown.Value = false;
     }
 
-    /// <summary>
-    /// Sets margin based on window state
-    /// </summary>
-    private static void SetMargin(MainViewModel vm, Window window)
-    {
-        if (Settings.WindowProperties.Maximized)
-        {
-            // Sometimes margin is 0 when it's not supposed to be, so replace with 7. Not sure why.
-            var left = window.OffScreenMargin.Left is 0 ? 7 : window.OffScreenMargin.Left;
-            var top = window.OffScreenMargin.Top is 0 ? 7 : window.OffScreenMargin.Top;
-            var right = window.OffScreenMargin.Right is 0 ? 7 : window.OffScreenMargin.Right;
-            var bottom = window.OffScreenMargin.Bottom is 0 ? 7 : window.OffScreenMargin.Bottom;
-            vm.MainWindow.TopScreenMargin.Value = new Thickness(left, top, right, 0);
-            vm.MainWindow.BottomScreenMargin.Value = new Thickness(left, 0, right, bottom);
-        }
-        else
-        {
-            var noThickness = new Thickness(0);
-            vm.MainWindow.TopScreenMargin.Value = noThickness;
-            vm.MainWindow.BottomScreenMargin.Value = noThickness;
-        }
-    }
-
     #endregion Helpers
 }

+ 96 - 1
src/PicView.Avalonia.Win32/WindowImpl/WindowInitializer.cs

@@ -4,13 +4,16 @@ using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Threading;
 using PicView.Avalonia.Functions;
 using PicView.Avalonia.Interfaces;
+using PicView.Avalonia.Printing;
 using PicView.Avalonia.Update;
 using PicView.Avalonia.ViewModels;
 using PicView.Avalonia.Win32.PlatformUpdate;
+using PicView.Avalonia.Win32.Printing;
 using PicView.Avalonia.Win32.Views;
 using PicView.Avalonia.WindowBehavior;
 using PicView.Core.Config;
 using PicView.Core.ViewModels;
+using R3;
 
 namespace PicView.Avalonia.Win32.WindowImpl;
 
@@ -24,6 +27,7 @@ public class WindowInitializer : IPlatformSpecificUpdate
     private KeybindingsWindow? _keybindingsWindow;
     private SettingsWindow? _settingsWindow;
     private SingleImageResizeWindow? _singleImageResizeWindow;
+    private PrintPreviewWindow? _printPreviewWindow;
 
     public async Task HandlePlatofrmUpdate(UpdateInfo updateInfo, string tempPath)
     {
@@ -328,7 +332,7 @@ public class WindowInitializer : IPlatformSpecificUpdate
         }
 
         await FunctionsMapper.CloseMenus();
-        
+
         return;
 
         void Show()
@@ -429,4 +433,95 @@ public class WindowInitializer : IPlatformSpecificUpdate
             _ = FunctionsMapper.CloseMenus();
         }
     }
+    
+    public void ShowPrintPreviewWindow(MainViewModel vm)
+    {
+        if (Dispatcher.UIThread.CheckAccess())
+        {
+            Set();
+        }
+        else
+        {
+            Dispatcher.UIThread.InvokeAsync(Set);
+        }
+
+        return;
+
+        void Set()
+        {
+            if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
+            {
+                return;
+            }
+
+            if (_printPreviewWindow is null)
+            {
+                vm.PrintPreview = new();
+
+                var printerSettings = new System.Drawing.Printing.PrinterSettings();
+
+                // Load installed printers
+                vm.PrintPreview.Printers.Value = new List<string>(System.Drawing.Printing.PrinterSettings.InstalledPrinters.Cast<string>());
+                vm.PrintPreview.PaperSizes.Value = new List<string>(PrintEngine.GetPaperSizes(printerSettings.PrinterName));
+
+
+                // Pre-select default printer settings
+                var pageSettings = printerSettings.DefaultPageSettings;
+
+                var currentPrintSettings = new PrintSettings
+                {
+                    ImagePath = { Value = vm.PicViewer.FileInfo?.Value?.FullName },
+                    PrinterName = { Value = printerSettings.PrinterName },
+                    PaperSize = { Value = pageSettings.PaperSize.PaperName },
+                    ColorMode = { Value = printerSettings.SupportsColor ? (int)ColorModes.Auto : (int)ColorModes.BlackAndWhite },
+                    Orientation = { Value = pageSettings.Landscape ? (int)Orientations.Landscape : (int)Orientations.Portrait },
+                    MarginTop = { Value = PrintSettings.HundredthsInchToMm(pageSettings.Margins.Top) },
+                    MarginBottom = { Value = PrintSettings.HundredthsInchToMm(pageSettings.Margins.Bottom) },
+                    MarginLeft = { Value = PrintSettings.HundredthsInchToMm(pageSettings.Margins.Left) },
+                    MarginRight = { Value = PrintSettings.HundredthsInchToMm(pageSettings.Margins.Right) }
+                };
+
+                vm.PrintPreview.PrintSettings.Value = currentPrintSettings;
+
+                if (vm.PicViewer.FileInfo.Value != null && File.Exists(vm.PicViewer.FileInfo.Value.FullName))
+                {
+                    using var fs = File.OpenRead(vm.PicViewer.FileInfo.Value.FullName);
+                    vm.PrintPreview.PreviewImage.Value = new System.Drawing.Bitmap(fs);
+                }
+
+                _printPreviewWindow = new PrintPreviewWindow
+                {
+                    DataContext = vm,
+                    WindowStartupLocation = WindowStartupLocation.CenterOwner
+                };
+
+                vm.PrintPreview.PrintCommand.SubscribeAwait(async (_, ct) =>
+                {
+                    await _printPreviewWindow?.RunPrintAsync(vm);
+                })
+                .AddTo(vm.PrintPreview._disposables);
+
+                vm.PrintPreview.CancelCommand.SubscribeAwait(async (_, ct) =>
+                {
+                    await Dispatcher.UIThread.InvokeAsync(() => _printPreviewWindow?.Close());
+                }).AddTo(vm.PrintPreview._disposables);
+
+                _printPreviewWindow.Show(desktop.MainWindow);
+                _printPreviewWindow.Closing += (s, e) => _printPreviewWindow = null;
+            }
+            else
+            {
+                if (_printPreviewWindow.WindowState == WindowState.Minimized)
+                {
+                    WindowFunctions.ShowMinimizedWindow(_printPreviewWindow);
+                }
+                else
+                {
+                    _printPreviewWindow.Show();
+                }
+            }
+
+            _ = FunctionsMapper.CloseMenus();
+        }
+    }
 }

+ 24 - 0
src/PicView.Avalonia/Converters/BoolToThicknessConverter.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Globalization;
+using Avalonia;
+using Avalonia.Data;
+using Avalonia.Data.Converters;
+
+namespace PicView.Avalonia.Converters;
+
+public class BoolToThicknessConverter : IValueConverter
+{
+    public Thickness TrueThickness { get; set; } = new(0);
+    public Thickness FalseThickness { get; set; } = new(0);
+
+    public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+    {
+        if (value is bool b)
+            return b ? TrueThickness : FalseThickness;
+
+        return BindingOperations.DoNothing;
+    }
+
+    public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+        => BindingOperations.DoNothing;
+}

+ 3 - 0
src/PicView.Avalonia/PicView.Avalonia.csproj

@@ -119,6 +119,9 @@
           <DependentUpon>DateTimePickerButtons.axaml</DependentUpon>
           <SubType>Code</SubType>
       </Compile>
+      <Compile Update="Views\Main\PrintPreviewView.axaml.cs">
+          <DependentUpon>PrintPreviewView.axaml</DependentUpon>
+      </Compile>
   </ItemGroup>
 
 

+ 1 - 0
src/PicView.Avalonia/ViewModels/MainViewModel.cs

@@ -27,6 +27,7 @@ public class MainViewModel
     public ImageInfoWindowViewModel? InfoWindow { get; set; }
     public FileAssociationsViewModel? AssociationsViewModel { get; set; }
     public AboutViewModel? AboutView { get; set; }
+    public PrintPreviewViewModel? PrintPreview { get; set; }
 
     public MainViewModel(IPlatformSpecificService? platformSpecificService, IPlatformWindowService? platformWindowService)
     {

+ 12 - 6
src/PicView.Avalonia/Views/Gallery/GalleryItem.axaml

@@ -141,6 +141,7 @@
                                              Mode=OneWay}"
                     IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
                                                 Converter={x:Static ObjectConverters.IsNotNull}}"
+                    IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}"
                     x:Name="WallpaperMenuItem">
                     <MenuItem.Icon>
                         <Path
@@ -159,7 +160,8 @@
                         Header="{CompiledBinding Translation.Fill.Value,
                                                  Mode=OneWay}"
                         IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                    Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                    Converter={x:Static ObjectConverters.IsNotNull}}"
+                        IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                         <MenuItem.Icon>
                             <Path
                                 Data="{StaticResource PanoramaGeometry}"
@@ -178,7 +180,8 @@
                         Header="{CompiledBinding Translation.Fit.Value,
                                                  Mode=OneWay}"
                         IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                    Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                    Converter={x:Static ObjectConverters.IsNotNull}}"
+                        IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                         <MenuItem.Icon>
                             <Path
                                 Data="{StaticResource PanoramaGeometry}"
@@ -197,7 +200,8 @@
                         Header="{CompiledBinding Translation.Stretch.Value,
                                                  Mode=OneWay}"
                         IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                    Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                    Converter={x:Static ObjectConverters.IsNotNull}}"
+                        IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                         <MenuItem.Icon>
                             <Path
                                 Data="{StaticResource PanoramaGeometry}"
@@ -217,7 +221,8 @@
                         Header="{CompiledBinding Translation.Center.Value,
                                                  Mode=OneWay}"
                         IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                    Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                    Converter={x:Static ObjectConverters.IsNotNull}}"
+                        IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                         <MenuItem.Icon>
                             <Path
                                 Data="{StaticResource PanoramaGeometry}"
@@ -236,7 +241,8 @@
                         Header="{CompiledBinding Translation.Tile.Value,
                                                  Mode=OneWay}"
                         IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                    Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                    Converter={x:Static ObjectConverters.IsNotNull}}"
+                        IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                         <MenuItem.Icon>
                             <Path
                                 Data="{StaticResource PanoramaGeometry}"
@@ -247,7 +253,7 @@
                         </MenuItem.Icon>
                     </MenuItem>
                 </MenuItem>
-                <Separator />
+                <Separator IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}" />
 
                 <MenuItem
                     Command="{CompiledBinding Tools.CopyFileCommand}"

+ 3 - 2
src/PicView.Avalonia/Views/Main/EffectsView.axaml

@@ -53,7 +53,8 @@
                 CommandParameter="{CompiledBinding PicViewer.FileInfo.CurrentValue.FullName,
                                                    FallbackValue=''}"
                 Header="{CompiledBinding Translation.SetAsWallpaper.Value,
-                                         Mode=OneWay}">
+                                         Mode=OneWay}"
+                IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                 <MenuItem.Icon>
                     <Path
                         Data="{StaticResource PanoramaGeometry}"
@@ -63,7 +64,7 @@
                         Width="13" />
                 </MenuItem.Icon>
             </MenuItem>
-            <Separator />
+            <Separator IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}" />
             <MenuItem Header="{CompiledBinding Translation.ClearEffects.Value, Mode=OneWay}" x:Name="ClearEffectsItem">
                 <MenuItem.Icon>
                     <Image

+ 12 - 5
src/PicView.Avalonia/Views/Main/ImageInfoView.axaml

@@ -6,6 +6,7 @@
     x:DataType="vm:MainViewModel"
     xmlns="https://github.com/avaloniaui"
     xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls"
+    xmlns:converters="clr-namespace:PicView.Avalonia.Converters"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:uc="clr-namespace:PicView.Avalonia.Views.UC"
@@ -118,6 +119,7 @@
                                          Mode=OneWay}"
                 IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
                                             Converter={x:Static ObjectConverters.IsNotNull}}"
+                IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}"
                 x:Name="WallpaperMenuItem">
                 <MenuItem.Icon>
                     <Path
@@ -136,7 +138,8 @@
                     Header="{CompiledBinding Translation.Fill.Value,
                                              Mode=OneWay}"
                     IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                Converter={x:Static ObjectConverters.IsNotNull}}"
+                    IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource PanoramaGeometry}"
@@ -155,7 +158,8 @@
                     Header="{CompiledBinding Translation.Fit.Value,
                                              Mode=OneWay}"
                     IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                Converter={x:Static ObjectConverters.IsNotNull}}"
+                    IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource PanoramaGeometry}"
@@ -174,7 +178,8 @@
                     Header="{CompiledBinding Translation.Stretch.Value,
                                              Mode=OneWay}"
                     IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                Converter={x:Static ObjectConverters.IsNotNull}}"
+                    IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource PanoramaGeometry}"
@@ -194,7 +199,8 @@
                     Header="{CompiledBinding Translation.Center.Value,
                                              Mode=OneWay}"
                     IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                Converter={x:Static ObjectConverters.IsNotNull}}"
+                    IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource PanoramaGeometry}"
@@ -213,7 +219,8 @@
                     Header="{CompiledBinding Translation.Tile.Value,
                                              Mode=OneWay}"
                     IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                                Converter={x:Static ObjectConverters.IsNotNull}}">
+                                                Converter={x:Static ObjectConverters.IsNotNull}}"
+                    IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                     <MenuItem.Icon>
                         <Path
                             Data="{StaticResource PanoramaGeometry}"

+ 3 - 2
src/PicView.Avalonia/Views/Main/MainView.axaml

@@ -681,7 +681,8 @@
                 Header="{CompiledBinding Translation.SetAsWallpaper.Value,
                                          Mode=OneWay}"
                 IsEnabled="{CompiledBinding PicViewer.ImageSource.Value,
-                                            Converter={x:Static ObjectConverters.IsNotNull}}">
+                                            Converter={x:Static ObjectConverters.IsNotNull}}"
+                IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}">
                 <MenuItem.Icon>
                     <Path
                         Data="{StaticResource PanoramaGeometry}"
@@ -692,7 +693,7 @@
                 </MenuItem.Icon>
             </MenuItem>
 
-            <Separator />
+            <Separator IsVisible="{CompiledBinding GlobalSettings.ShowSetAsWallpaper.Value}" />
 
             <!--  Image  -->
             <MenuItem Header="{CompiledBinding Translation.Image.Value, Mode=OneWay}">

+ 283 - 0
src/PicView.Avalonia/Views/Main/PrintPreviewView.axaml

@@ -0,0 +1,283 @@
+<UserControl
+    x:Class="PicView.Avalonia.Views.Main.PrintPreviewView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:uc="clr-namespace:PicView.Avalonia.Views.UC"
+	xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls"
+    xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels"
+    mc:Ignorable="d"
+    x:DataType="viewModels:MainViewModel"
+    Width="850"
+    Height="700">
+
+	<Panel>
+		<!-- Spinner overlay -->
+		<uc:SpinWaiter
+            HorizontalAlignment="Center" VerticalAlignment="Center" ZIndex="100"
+            IsVisible="{CompiledBinding PrintPreview.IsProcessing.Value, Mode=OneWay}"  />
+		
+		<!-- Root grid with two columns -->
+		<Grid RowDefinitions="*,Auto" ColumnDefinitions="2*,3*" Margin="10"
+			  Opacity="{CompiledBinding PrintPreview.Opacity.Value, Mode=OneWay}"
+			  IsHitTestVisible="{CompiledBinding !PrintPreview.IsProcessing.Value, Mode=OneWay}">
+
+			<!-- Settings Panel (Left) -->
+			<StackPanel Grid.Row="0" Grid.Column="0" Spacing="12">
+
+				<!-- Printer -->
+				<TextBlock 
+					Text="{CompiledBinding Translation.Printer.Value, Mode=OneWay}" 
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+
+				<ComboBox
+                    Background="{DynamicResource SecondaryBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1"
+                    FontFamily="/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Margin="0,0,0,4"
+                    Padding="5,7,0,7"
+				    ItemsSource="{CompiledBinding PrintPreview.Printers.Value}"
+                    SelectedItem="{CompiledBinding PrintPreview.PrintSettings.Value.PrinterName.Value, Mode=TwoWay}" />
+				
+				<!-- Paper Size -->
+				<TextBlock 
+					Text="{CompiledBinding Translation.PaperSize.Value, Mode=OneWay}"
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+				
+				<ComboBox
+					Background="{DynamicResource SecondaryBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1"
+                    FontFamily="/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Margin="0,0,0,4"
+                    Padding="5,7,0,7"
+                    ItemsSource="{CompiledBinding PrintPreview.PaperSizes.Value}"
+                    SelectedItem="{CompiledBinding PrintPreview.PrintSettings.Value.PaperSize.Value, Mode=TwoWay}" />
+
+				<!-- Orientation -->
+				<TextBlock 
+					Text="{CompiledBinding Translation.Orientation.Value, Mode=OneWay}"
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+
+				<ComboBox
+					Background="{DynamicResource SecondaryBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1"
+                    FontFamily="/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Margin="0,0,0,4"
+                    Padding="5,7,0,7"
+                    ItemsSource="{CompiledBinding PrintPreview.Orientations.Value}"
+                    SelectedIndex="{CompiledBinding PrintPreview.PrintSettings.Value.Orientation.Value, Mode=TwoWay}" />
+
+				<!-- Scale Mode -->
+				<TextBlock 
+					Text="{CompiledBinding Translation.Scale.Value, Mode=OneWay}"
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+
+				<ComboBox
+					Background="{DynamicResource SecondaryBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1"
+                    FontFamily="/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Margin="0,0,0,4"
+                    Padding="5,7,0,7"
+                    ItemsSource="{CompiledBinding PrintPreview.ScaleModes.Value}"
+                    SelectedIndex="{CompiledBinding PrintPreview.PrintSettings.Value.ScaleMode.Value, Mode=TwoWay}" />
+
+				<!-- Color Mode -->
+				<TextBlock
+					Text="{CompiledBinding Translation.Color.Value, Mode=OneWay}"
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+
+				<ComboBox
+					Background="{DynamicResource SecondaryBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1"
+                    FontFamily="/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Margin="0,0,0,4"
+                    Padding="5,7,0,7"
+					ItemsSource="{CompiledBinding PrintPreview.ColorModes.Value}"
+                    SelectedIndex="{CompiledBinding PrintPreview.PrintSettings.Value.ColorMode.Value, Mode=TwoWay}"/>
+				
+				<!-- Copies -->
+				
+				<TextBlock 
+					Text="{CompiledBinding Translation.Copies.Value, Mode=OneWay}"
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+
+				<NumericUpDown
+					Background="{DynamicResource SecondaryBackgroundColor}"
+                    BorderBrush="{DynamicResource MainBorderColor}"
+                    BorderThickness="1"
+                    FontFamily="/Assets/Fonts/Roboto-Medium.ttf#Roboto"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Margin="0,0,0,4"
+                    Padding="5,7,0,7"
+					Minimum="1"
+					Maximum="200"
+					Increment="1"
+					Value="{CompiledBinding PrintPreview.PrintSettings.Value.Copies.Value, Mode=TwoWay}" />
+
+				<!-- Margins -->
+				<TextBlock
+					Text="{CompiledBinding Translation.Margins.Value, Mode=OneWay}"
+					Classes="txt"
+					FontFamily="/Assets/Fonts/Roboto-Bold.ttf#Roboto"
+					FontSize="14"
+					Foreground="{StaticResource SecondaryTextColor}"
+					Margin="0,6,0,0" />
+
+				<Grid ColumnDefinitions="*,*,*,*"
+					  Margin="0,0,0,0"
+					  ColumnSpacing="6">
+
+					<!-- Top -->
+					<StackPanel Grid.Column="0">
+						<TextBlock Text="{CompiledBinding Translation.Top.Value, Mode=OneWay}"
+								   Foreground="{StaticResource SecondaryTextColor}"
+								   FontSize="12"
+								   Margin="0,0,0,2" />
+						<NumericUpDown Minimum="0" Maximum="100" Increment="1"
+									   Value="{CompiledBinding PrintPreview.PrintSettings.Value.MarginTop.Value, Mode=TwoWay}"
+									   HorizontalAlignment="Stretch"/>
+					</StackPanel>
+
+					<!-- Bottom -->
+					<StackPanel Grid.Column="1">
+						<TextBlock Text="{CompiledBinding Translation.Bottom.Value, Mode=OneWay}"
+								   Foreground="{StaticResource SecondaryTextColor}"
+								   FontSize="12"
+								   Margin="0,0,0,2" />
+						<NumericUpDown Minimum="0" Maximum="100" Increment="1"
+									   Value="{CompiledBinding PrintPreview.PrintSettings.Value.MarginBottom.Value, Mode=TwoWay}"
+									   HorizontalAlignment="Stretch"/>
+					</StackPanel>
+
+					<!-- Left -->
+					<StackPanel Grid.Column="2">
+						<TextBlock Text="{CompiledBinding Translation.Left.Value, Mode=OneWay}"
+								   Foreground="{StaticResource SecondaryTextColor}"
+								   FontSize="12"
+								   Margin="0,0,0,2" />
+						<NumericUpDown Minimum="0" Maximum="100" Increment="1"
+									   Value="{CompiledBinding PrintPreview.PrintSettings.Value.MarginLeft.Value, Mode=TwoWay}"
+									   HorizontalAlignment="Stretch"/>
+					</StackPanel>
+
+					<!-- Right -->
+					<StackPanel Grid.Column="3">
+						<TextBlock Text="{CompiledBinding Translation.Right.Value, Mode=OneWay}"
+								   Foreground="{StaticResource SecondaryTextColor}"
+								   FontSize="12"
+								   Margin="0,0,0,2" />
+						<NumericUpDown Minimum="0" Maximum="100" Increment="1"
+									   Value="{CompiledBinding PrintPreview.PrintSettings.Value.MarginRight.Value, Mode=TwoWay}"
+									   HorizontalAlignment="Stretch"/>
+					</StackPanel>
+				</Grid>
+
+
+
+			</StackPanel>
+
+			<!-- Preview Panel (Right) -->
+			<Border Grid.Row="0" Grid.Column="1" Background="{DynamicResource DisabledBackgroundColor}" Margin="20, 20, 20, 20" CornerRadius="6">
+				<Viewbox Stretch="Uniform" StretchDirection="Both" Margin="10">
+					<Border Width="{CompiledBinding PrintPreview.PageWidth.Value}"
+									Height="{CompiledBinding PrintPreview.PageHeight.Value}"
+									Background="White"
+									BorderBrush="LightGray"
+									BorderThickness="1"
+									CornerRadius="2"
+									Margin="20">
+						<Border.Effect>
+							<DropShadowEffect Color="Black"
+							  BlurRadius="15"
+							  OffsetX="4"
+							  OffsetY="4"
+							  Opacity="0.3"/>
+						</Border.Effect>
+
+						<Image Source="{CompiledBinding PrintPreview.PreviewImage.Value}" Stretch="Fill" />
+					</Border>
+				</Viewbox>
+			</Border>
+
+
+
+			<Rectangle Grid.Row="1" Grid.ColumnSpan="2"
+					   Height="1"
+					   Fill="{DynamicResource MainBorderColor}"
+					   VerticalAlignment="Top" />
+
+			<!-- Footer Buttons -->
+			<StackPanel Grid.Row="2" Grid.ColumnSpan="2"
+                        Orientation="Horizontal"
+                        HorizontalAlignment="Right"
+                        Spacing="8"
+                        Margin="0,10,0,0">
+
+				<customControls:TextIconButton x:Name="PrintButton"
+                    Background="{DynamicResource AccentColor}"
+                    Classes="ButtonBorder accentHover"
+                    Command="{CompiledBinding PrintPreview.PrintCommand}"
+                    Data="{StaticResource PrintGeometry}"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Height="46"
+					Width="120"
+                    IconHeight="17"
+                    IconMargin="9,0,9,0"
+                    IconWidth="17"
+                    Text="{CompiledBinding Translation.Print.Value, Mode=OneWay}"
+                    ToolTip.Tip="{CompiledBinding Translation.Print.Value, Mode=OneWay}"
+					TextMargin="16,0,16,0"/>
+
+				<customControls:TextIconButton x:Name="CancelButton"
+                    Background="{DynamicResource MenuButtonColor}"
+                    Classes="ButtonBorder altHover"
+                    Command="{CompiledBinding PrintPreview.CancelCommand}"
+                    Data="{StaticResource CloseGeometry}"
+                    Foreground="{DynamicResource MainTextColor}"
+                    Height="46"
+					Width="120"
+                    IconHeight="17"
+                    IconMargin="9,0,9,0"
+                    IconWidth="17"
+                    Text="{CompiledBinding Translation.Cancel.Value, Mode=OneWay}"
+                    ToolTip.Tip="{CompiledBinding Translation.Cancel.Value, Mode=OneWay}"
+					TextMargin="16,0,16,0" />
+			</StackPanel>
+		</Grid>
+	</Panel>
+</UserControl>

+ 40 - 0
src/PicView.Avalonia/Views/Main/PrintPreviewView.axaml.cs

@@ -0,0 +1,40 @@
+using System.Runtime.InteropServices;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+using Avalonia.Styling;
+using PicView.Avalonia.Interfaces;
+using PicView.Avalonia.Update;
+using PicView.Core.Config;
+using PicView.Core.Localization;
+
+namespace PicView.Avalonia.Views.Main;
+
+public partial class PrintPreviewView : UserControl
+{
+    public required IPlatformSpecificUpdate PlatformUpdate;
+
+    public PrintPreviewView()
+    {
+        InitializeComponent();
+        Loaded += (_, _) =>
+        {
+
+            if (!Settings.Theme.Dark && !Settings.Theme.GlassTheme)
+            {
+                if (!Application.Current.TryGetResource("MainTextColor",
+                        Application.Current.RequestedThemeVariant, out var textColor))
+                {
+                    return;
+                }
+
+                if (textColor is not Color color)
+                {
+                    return;
+                }
+            }
+        };
+    }
+
+}

+ 6 - 4
src/PicView.Avalonia/Views/UC/BottomBar.axaml

@@ -8,11 +8,13 @@
     xmlns="https://github.com/avaloniaui"
     xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls"
     xmlns:viewModels="clr-namespace:PicView.Avalonia.ViewModels"
+    xmlns:converters="clr-namespace:PicView.Avalonia.Converters;assembly=PicView.Avalonia"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
     <UserControl.Resources>
         <SolidColorBrush Color="{DynamicResource MainTextColor}" x:Key="ImageMenuBrush" />
         <SolidColorBrush Color="{DynamicResource MainTextColor}" x:Key="ToolsMenuBrush" />
+        <converters:BoolToThicknessConverter x:Key="AllowResizeMarginConverter" TrueThickness="0,0,10,0" FalseThickness="0" />
     </UserControl.Resources>
 
     <UserControl.ContextMenu>
@@ -205,7 +207,7 @@
                                  Mode=OneWay}"
         x:Name="MainBottomBorder">
         <Panel>
-            <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
+            <StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Margin="{CompiledBinding MainWindow.CanResize.Value, Mode=OneWay, Converter={StaticResource AllowResizeMarginConverter}}">
 
                 <customControls:IconButton
                     Background="{DynamicResource SecondaryButtonBackgroundColor}"
@@ -310,7 +312,7 @@
                     IsEnabled="{CompiledBinding PicViewer.FileInfo.Value,
                                                 Converter={x:Static ObjectConverters.IsNotNull}}"
                     IsTabStop="False"
-                    Width="90"
+                    Width="80"
                     x:Name="PreviousButton" />
 
                 <customControls:IconButton
@@ -328,7 +330,7 @@
                     IsEnabled="{CompiledBinding PicViewer.FileInfo.Value,
                                                 Converter={x:Static ObjectConverters.IsNotNull}}"
                     IsTabStop="False"
-                    Width="90"
+                    Width="80"
                     x:Name="NextButton" />
 
                 <customControls:IconButton
@@ -440,7 +442,7 @@
                 HorizontalAlignment="Right"
                 IsVisible="{CompiledBinding MainWindow.CanResize.Value,
                                             Mode=OneWay}"
-                Margin="0,0,5,5"
+                Margin="0,0,2,2"
                 Stretch="Fill"
                 Stroke="{DynamicResource MainBackgroundColor}"
                 StrokeThickness="1"

+ 1 - 2
src/PicView.Avalonia/Views/UC/TitleTextBox.axaml

@@ -1,7 +1,6 @@
 <UserControl
     Background="{DynamicResource SecondaryBackgroundColor}"
-    MaxWidth="{CompiledBinding MainWindow.TitleMaxWidth.Value,
-                               Mode=OneWay}"
+    HorizontalAlignment="Stretch"
     d:DesignHeight="450"
     d:DesignWidth="800"
     mc:Ignorable="d"

+ 3 - 0
src/PicView.Avalonia/Wallpaper/WallpaperManager.cs

@@ -15,6 +15,9 @@ public static class WallpaperManager
             return;
         }
         
+        if (!vm.GlobalSettings.ShowSetAsWallpaper.Value)
+            return;
+        
         vm.MainWindow.IsLoadingIndicatorShown.Value = true;
         try
         {

+ 10 - 0
src/PicView.Core/Config/AppSettings.cs

@@ -193,6 +193,16 @@ public class UIProperties
     /// Indicates whether the application limits the background color to just behind the picture.
     /// </summary>
     public bool IsConstrainBackgroundColorEnabled { get; set; } = false;
+
+    /// <summary>
+    /// Indicates whether the application uses the inbuilt print preview window for printing
+    /// </summary>
+    public bool ShowPrintPreview { get; set; } = true;
+
+    /// <summary>
+    /// Shows the "Set as Wallpaper" option int the menus.
+    /// </summary>
+    public bool ShowSetAsWallpaper { get; set; } = true;
 }
 
 public class Theme

+ 8 - 0
src/PicView.Core/Config/Languages/da.json

@@ -30,6 +30,7 @@
   "BitDepth": "Bit dybde",
   "BlackAndWhite": "Sort/hvid",
   "Blur": "Sløring",
+  "Bottom": "Bund",
   "BottomGalleryItemSize": "Billedstørrelse i bundgalleriet",
   "BottomGalleryThumbnailStretch": "Udstrækning af billeder i bundgalleriet",
   "Brightness": "Lysstyrke",
@@ -53,6 +54,7 @@
   "CloseGallery": "Luk galleri",
   "CloseWindowPrompt": "Vil du lukke vinduet?",
   "CloudyWeather": "Overskyet vejr",
+  "Color": "Farve",
   "ColorPickerTool": "Farvevælgningsværktøj",
   "ColorPickerToolTooltip": "Vælg en farve fra billedet",
   "ColorRepresentation": "Farverepræsentation",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Konverteret til base64",
   "CoolWhiteFluorescent": "Kold hvid fluorescerende",
   "CopiedImage": "Kopier billede til udklipsholderen",
+  "Copies": "Kopier",
   "Copy": "Kopier",
   "CopyFile": "Kopier fil",
   "CopyImage": "Kopier billede",
@@ -204,6 +207,7 @@
   "Lossy": "Delvis tab af kvalitet",
   "Low": "Lav",
   "Manual": "Manuel",
+  "Margins": "Margener (mm)",
   "MaxAperture": "Maks blænde",
   "Maximize": "Maksimer",
   "MegaPixels": "megapixels",
@@ -254,6 +258,7 @@
   "Orientation": "Orientering",
   "OutputFolder": "Destination",
   "Pan": "Panorering",
+  "PaperSize": "Papirstørrelse",
   "PasswordArchive": "Adgangskodebeskyttet arkiv understøttes ikke",
   "PasteImageFromClipholder": "Indsæt billede fra udklipsholderen",
   "PencilSketch": "Blyantskitse",
@@ -272,6 +277,7 @@
   "Print": "Print",
   "PrintSizeCm": "Print str. (cm)",
   "PrintSizeIn": "Print str. (inch)",
+  "Printer": "Printer",
   "Quality": "Kvalitet",
   "Random": "Vilkårlig",
   "RawCamera": "Rå Kamera",
@@ -299,6 +305,7 @@
   "Save": "Gem",
   "SaveAs": "Gem som",
   "SavingFileFailed": "Gemning af fil mislykkedes",
+  "Scale": "Skalering",
   "ScrollAndRotate": "Scroll og roter",
   "ScrollDirection": "Scroll retning",
   "ScrollDown": "Scroll ned",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Slå looping til/fra",
   "ToggleScroll": "Slå scroll til/fra",
   "ToggleTaskbarProgress": "Vis fremskridt i proceslinjen",
+  "Top": "Top",
   "UnableToRender": "Kan ikke gengive billedet",
   "Unassociate": "Fjern tilknytning",
   "Uncalibrated": "Ikke kalibreret",

+ 8 - 0
src/PicView.Core/Config/Languages/de.json

@@ -30,6 +30,7 @@
   "BitDepth": "Farbtiefe",
   "BlackAndWhite": "Schwarz & Weiß",
   "Blur": "Verwischen",
+  "Bottom": "Unten",
   "BottomGalleryItemSize": "Größe der Miniaturansichten in der unteren Galerie",
   "BottomGalleryThumbnailStretch": "Miniaturbild-Erweiterung in der unteren Galerie",
   "Brightness": "Helligkeit",
@@ -53,6 +54,7 @@
   "CloseGallery": "Galerie schließen",
   "CloseWindowPrompt": "Möchten Sie das Fenster schließen?",
   "CloudyWeather": "Bewölktes Wetter",
+  "Color": "Farbe",
   "ColorPickerTool": "Farbauswahl-Werkzeug",
   "ColorPickerToolTooltip": "Farbe aus Bild auswählen",
   "ColorRepresentation": "Farbdarstellung",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "In Base64 umgewandelt",
   "CoolWhiteFluorescent": "Kaltweiß fluoreszierend",
   "CopiedImage": "Bild in Zwischenablage kopiert",
+  "Copies": "Kopien",
   "Copy": "Kopieren",
   "CopyFile": "Datei kopieren",
   "CopyImage": "Bild kopieren",
@@ -204,6 +207,7 @@
   "Lossy": "Verlustbehaftet",
   "Low": "Niedrig",
   "Manual": "Manuell",
+  "Margins": "Ränder (mm)",
   "MaxAperture": "Maximale Blende",
   "Maximize": "Maximieren",
   "MegaPixels": "Megapixel",
@@ -254,6 +258,7 @@
   "Orientation": "Orientierung",
   "OutputFolder": "Zielordner",
   "Pan": "Schwenken",
+  "PaperSize": "Papiergröße",
   "PasswordArchive": "Passwort geschützte Archive werden nicht unterstützt",
   "PasteImageFromClipholder": "Bild von Zwischenablage einfügen",
   "PencilSketch": "Bleistiftskizze",
@@ -272,6 +277,7 @@
   "Print": "Drucken",
   "PrintSizeCm": "Druckgröße (cm)",
   "PrintSizeIn": "Druckgröße (in)",
+  "Printer": "Drucker",
   "Quality": "Qualität",
   "Random": "Zufall",
   "RawCamera": "Rohkamera",
@@ -299,6 +305,7 @@
   "Save": "Speichern",
   "SaveAs": "Speichern unter",
   "SavingFileFailed": "Speichern der Datei fehlgeschlagen",
+  "Scale": "Maßstab",
   "ScrollAndRotate": "Scrollen und drehen",
   "ScrollDirection": "Scrollrichtung",
   "ScrollDown": "Nach unten scrollen",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Wiederholung ein-/ausschalten",
   "ToggleScroll": "Scrollen umschalten",
   "ToggleTaskbarProgress": "Fortschritt in der Taskleiste anzeigen",
+  "Top": "Oben",
   "UnableToRender": "Bild kann nicht gerendert werden",
   "Unassociate": "Aufhebung der Zuordnung",
   "Uncalibrated": "Nicht kalibriert",

+ 10 - 1
src/PicView.Core/Config/Languages/en.json

@@ -408,5 +408,14 @@
   "_2Star": "2 star rating",
   "_3Star": "3 star rating",
   "_4Star": "4 star rating",
-  "_5Star": "5 star rating"
+  "_5Star": "5 star rating",
+
+  "Printer": "Printer",
+  "PaperSize": "Paper Size",
+  "Scale": "Scale",
+  "Color": "Color",
+  "Copies": "Copies",
+  "Margins": "Margins (mm)",
+  "Top": "Top",
+  "Bottom": "Bottom"
 }

+ 8 - 0
src/PicView.Core/Config/Languages/es.json

@@ -30,6 +30,7 @@
   "BitDepth": "Profundidad de bits",
   "BlackAndWhite": "Blanco y Negro",
   "Blur": "Desenfoque",
+  "Bottom": "Inferior",
   "BottomGalleryItemSize": "Elementos de la galería inferior",
   "BottomGalleryThumbnailStretch": "Estiramiento de miniatura de la galería inferior",
   "Brightness": "Brillo",
@@ -53,6 +54,7 @@
   "CloseGallery": "Cerrar galería",
   "CloseWindowPrompt": "¿Desea cerrar la ventana?",
   "CloudyWeather": "Tiempo nublado",
+  "Color": "Color",
   "ColorPickerTool": "Cuentagotas",
   "ColorPickerToolTooltip": "Elegir color desde imagen",
   "ColorRepresentation": "Representación de color",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Convertido a base64",
   "CoolWhiteFluorescent": "Fluorescente blanco frío",
   "CopiedImage": "Copiar imagen al portapapeles",
+  "Copies": "Copias",
   "Copy": "Copiar",
   "CopyFile": "Copiar archivo",
   "CopyImage": "Copiar imagen",
@@ -204,6 +207,7 @@
   "Lossy": "Lossy",
   "Low": "Bajo",
   "Manual": "Manual",
+  "Margins": "Márgenes (mm)",
   "MaxAperture": "Apertura máxima",
   "Maximize": "Maximizar",
   "MegaPixels": "megapixeles",
@@ -254,6 +258,7 @@
   "Orientation": "Orientación",
   "OutputFolder": "Carpeta de salida",
   "Pan": "Ajustar Tamaño",
+  "PaperSize": "Tamaño de papel",
   "PasswordArchive": "Archivo protegido por contraseña no soportado",
   "PasteImageFromClipholder": "Pegar imagen desde portapapeles",
   "PencilSketch": "Dibujo a lápiz",
@@ -272,6 +277,7 @@
   "Print": "Imprimir",
   "PrintSizeCm": "Tamaño de impresión (cm)",
   "PrintSizeIn": "Tamaño de impresión (in)",
+  "Printer": "Impresora",
   "Quality": "Calidad",
   "Random": "Aleatorio",
   "RawCamera": "Cámara Raw",
@@ -299,6 +305,7 @@
   "Save": "Guardar",
   "SaveAs": "Guardar como",
   "SavingFileFailed": "Guardando archivo fallido",
+  "Scale": "Escala",
   "ScrollAndRotate": "Desplazar y rotar",
   "ScrollDirection": "Dirección de desplazamiento",
   "ScrollDown": "Desplazar hacia abajo",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Alternar bucles",
   "ToggleScroll": "Alternar desplazamiento",
   "ToggleTaskbarProgress": "Mostrar el progreso en la barra de tareas",
+  "Top": "Superior",
   "UnableToRender": "No se puede renderizar la imagen",
   "Unassociate": "Desasociar",
   "Uncalibrated": "Sin calibrar",

+ 8 - 0
src/PicView.Core/Config/Languages/fr.json

@@ -30,6 +30,7 @@
   "BitDepth": "Profondeur",
   "BlackAndWhite": "Noir & blanc",
   "Blur": "Flouter",
+  "Bottom": "Bas",
   "BottomGalleryItemSize": "Éléments de la galerie inférieure",
   "BottomGalleryThumbnailStretch": "Estirer les miniatures de la galerie inférieure",
   "Brightness": "Luminosité",
@@ -53,6 +54,7 @@
   "CloseGallery": "Fermer la galerie",
   "CloseWindowPrompt": "Souhaitez-vous fermer la fenêtre ?",
   "CloudyWeather": "Temps nuageux",
+  "Color": "Couleur",
   "ColorPickerTool": "Outil de sélection de couleur",
   "ColorPickerToolTooltip": "Choisir la couleur de l'image",
   "ColorRepresentation": "Représentation des couleurs",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Converti en base64",
   "CoolWhiteFluorescent": "Fluorescent blanc froid",
   "CopiedImage": "Copier l'image dans le presse-papiers",
+  "Copies": "Copies",
   "Copy": "Copier",
   "CopyFile": "Copier le fichier",
   "CopyImage": "Copier l'image",
@@ -204,6 +207,7 @@
   "Lossy": "Avec perte",
   "Low": "Faible",
   "Manual": "Manuel",
+  "Margins": "Marges (mm)",
   "MaxAperture": "Ouverture maximale",
   "Maximize": "Maximiser",
   "MegaPixels": "mégapixels",
@@ -254,6 +258,7 @@
   "Orientation": "Orientation",
   "OutputFolder": "Dossier de sortie",
   "Pan": "Panoramique",
+  "PaperSize": "Taille du papier",
   "PasswordArchive": "Archive protégée par mot de passe non supportée",
   "PasteImageFromClipholder": "Coller l'image à partir du support de clip",
   "PencilSketch": "Croquis au crayon",
@@ -272,6 +277,7 @@
   "Print": "Imprimer",
   "PrintSizeCm": "Taille d'impression (cm)",
   "PrintSizeIn": "Taille d'impression (in)",
+  "Printer": "Imprimante",
   "Quality": "Qualité",
   "Random": "Aléatoire",
   "RawCamera": "Caméra Raw",
@@ -299,6 +305,7 @@
   "Save": "Enregistrer",
   "SaveAs": "Enregistrer sous",
   "SavingFileFailed": "La sauvegarde du fichier a échoué",
+  "Scale": "Échelle",
   "ScrollAndRotate": "Faire défiler et tourner",
   "ScrollDirection": "Direction du défilement",
   "ScrollDown": "Faire défiler vers le bas",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Basculer en boucle",
   "ToggleScroll": "Activer le défilement",
   "ToggleTaskbarProgress": "Afficher la progression dans la barre des tâches",
+  "Top": "Haut",
   "UnableToRender": "Impossible de rendre l'image",
   "Unassociate": "Dissocier",
   "Uncalibrated": "Non calibré",

+ 8 - 0
src/PicView.Core/Config/Languages/he.json

@@ -30,6 +30,7 @@
   "BitDepth": "עומק סיביות",
   "BlackAndWhite": "גווני אפור",
   "Blur": "טשטוש",
+  "Bottom": "תחתונה",
   "BottomGalleryItemSize": "גודל תמונות ממוזערות בגלריה התחתונה",
   "BottomGalleryThumbnailStretch": "מתיחת תמונות ממוזערות בגלריה התחתונה",
   "Brightness": "בהירות",
@@ -53,6 +54,7 @@
   "CloseGallery": "סגור גלריה",
   "CloseWindowPrompt": "לסגור את החלון?",
   "CloudyWeather": "מזג אוויר מעונן",
+  "Color": "צבע",
   "ColorPickerTool": "דוגם צבעים",
   "ColorPickerToolTooltip": "בחר צבע מהתמונה",
   "ColorRepresentation": "ייצוג צבע",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "הומר ל-Base64",
   "CoolWhiteFluorescent": "אור פלואורסצנט לבן קריר",
   "CopiedImage": "התמונה הועתקה ללוח",
+  "Copies": "עותקים",
   "Copy": "העתק",
   "CopyFile": "העתק קובץ",
   "CopyImage": "העתק תמונה",
@@ -204,6 +207,7 @@
   "Lossy": "עם איבוד נתונים",
   "Low": "נמוך",
   "Manual": "ידני",
+  "Margins": "שוליים (מ״מ)",
   "MaxAperture": "צמצם מרבי",
   "Maximize": "הגדל למקסימום",
   "MegaPixels": "מגה פיקסלים",
@@ -254,6 +258,7 @@
   "Orientation": "כיוון",
   "OutputFolder": "תיקיית פלט",
   "Pan": "הזזה",
+  "PaperSize": "גודל נייר",
   "PasswordArchive": "ארכיון מוגן בסיסמה אינו נתמך",
   "PasteImageFromClipholder": "הדבק תמונה מלוח העריכה",
   "PencilSketch": "רישום בעיפרון",
@@ -272,6 +277,7 @@
   "Print": "הדפס",
   "PrintSizeCm": "גודל הדפסה (ס\"מ)",
   "PrintSizeIn": "גודל הדפסה (אינץ')",
+  "Printer": "מדפסת",
   "Quality": "איכות",
   "Random": "אקראי",
   "RawCamera": "מצלמת RAW",
@@ -299,6 +305,7 @@
   "Save": "שמור",
   "SaveAs": "שמור בשם",
   "SavingFileFailed": "שמירת הקובץ נכשלה",
+  "Scale": "קנה מידה",
   "ScrollAndRotate": "גלול וסובב",
   "ScrollDirection": "כיוון גלילה",
   "ScrollDown": "גלול מטה",
@@ -373,6 +380,7 @@
   "ToggleLooping": "החלף מצב נגינה חוזרת",
   "ToggleScroll": "החלף מצב גלילה",
   "ToggleTaskbarProgress": "הצג התקדמות בשורת המשימות",
+  "Top": "עליונה",
   "UnableToRender": "לא ניתן להציג את התמונה",
   "Unassociate": "בטל שיוך",
   "Uncalibrated": "לא מכויל",

+ 8 - 0
src/PicView.Core/Config/Languages/hu.json

@@ -30,6 +30,7 @@
   "BitDepth": "Bitmélység",
   "BlackAndWhite": "Fekete -fehér",
   "Blur": "Homályosít",
+  "Bottom": "Alsó",
   "BottomGalleryItemSize": "A miniatűrök mérete az alsó galériában",
   "BottomGalleryThumbnailStretch": "Miniatűr nyújtása az alsó galériában",
   "Brightness": "Fényerő",
@@ -53,6 +54,7 @@
   "CloseGallery": "Galéria bezárása",
   "CloseWindowPrompt": "Be akarja zárni az ablakot?",
   "CloudyWeather": "Felhős idő",
+  "Color": "Szín",
   "ColorPickerTool": "Színválasztó eszköz",
   "ColorPickerToolTooltip": "Válasszon színt a képről",
   "ColorRepresentation": "Színes ábrázolás",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Base64-re konvertálva",
   "CoolWhiteFluorescent": "Hűvös fehér fluoreszkáló",
   "CopiedImage": "Másolt kép a vágólapra",
+  "Copies": "Másolatok",
   "Copy": "Másolás",
   "CopyFile": "Fájl másolása",
   "CopyImage": "Kép másolása",
@@ -204,6 +207,7 @@
   "Lossy": "Veszteséges",
   "Low": "Alacsony",
   "Manual": "Kézi",
+  "Margins": "Margók (mm)",
   "MaxAperture": "Maximális rekesznyílás",
   "Maximize": "Maximalizál",
   "MegaPixels": "megapixel",
@@ -254,6 +258,7 @@
   "Orientation": "Tájolás",
   "OutputFolder": "Kimeneti mappa",
   "Pan": "Fordítás",
+  "PaperSize": "Papírméret",
   "PasswordArchive": "Jelszóval védett archívum nem támogatott",
   "PasteImageFromClipholder": "Kép beillesztése a kliptartóból",
   "PencilSketch": "Ceruza vázlat",
@@ -272,6 +277,7 @@
   "Print": "Nyomtatás",
   "PrintSizeCm": "Nyomtatási méret (cm)",
   "PrintSizeIn": "Nyomtatási méret (hüvelyk)",
+  "Printer": "Nyomtató",
   "Quality": "Minőség",
   "Random": "Véletlen",
   "RawCamera": "Raw kamera",
@@ -299,6 +305,7 @@
   "Save": "Mentés",
   "SaveAs": "Mentés másként",
   "SavingFileFailed": "A fájl mentése sikertelen",
+  "Scale": "Méretarány",
   "ScrollAndRotate": "Görgetés és forgatás",
   "ScrollDirection": "Görgetési irány",
   "ScrollDown": "Görgessen lefelé",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Hurkolás váltása",
   "ToggleScroll": "Görgetés váltása",
   "ToggleTaskbarProgress": "A tálca előrehaladásának megjelenítése",
+  "Top": "Felső",
   "UnableToRender": "Nem lehet renderelni a képet",
   "Unassociate": "Nem társított",
   "Uncalibrated": "Kalibrálatlan",

+ 8 - 0
src/PicView.Core/Config/Languages/it.json

@@ -30,6 +30,7 @@
   "BitDepth": "Profondità di bit",
   "BlackAndWhite": "Bianco e nero",
   "Blur": "Blur",
+  "Bottom": "Inferiore",
   "BottomGalleryItemSize": "Elementi galleria inferiore",
   "BottomGalleryThumbnailStretch": "Estiramento miniature galleria inferiore",
   "Brightness": "Luminosità",
@@ -53,6 +54,7 @@
   "CloseGallery": "Chiudi la galleria",
   "CloseWindowPrompt": "Vuoi chiudere la finestra?",
   "CloudyWeather": "Tempo nuvoloso",
+  "Color": "Colore",
   "ColorPickerTool": "Strumento di selezione del colore",
   "ColorPickerToolTooltip": "Scegli il colore dall'immagine",
   "ColorRepresentation": "Rappresentazione del colore",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Convertito in base64",
   "CoolWhiteFluorescent": "Fluorescente bianco freddo",
   "CopiedImage": "Immagine copiata negli appunti",
+  "Copies": "Copie",
   "Copy": "Copia",
   "CopyFile": "Copia il file",
   "CopyImage": "Copia l'immagine",
@@ -204,6 +207,7 @@
   "Lossy": "Con perdita",
   "Low": "Basso",
   "Manual": "Manuale",
+  "Margins": "Margini (mm)",
   "MaxAperture": "Apertura massima",
   "Maximize": "Massimizzare",
   "MegaPixels": "Megapixel",
@@ -254,6 +258,7 @@
   "Orientation": "Orientamento",
   "OutputFolder": "Cartella di uscita",
   "Pan": "Fare una panoramica",
+  "PaperSize": "Formato carta",
   "PasswordArchive": "Archivio protetto da password non supportato",
   "PasteImageFromClipholder": "Incolla l'immagine dagli appunti",
   "PencilSketch": "Schizzo a matita",
@@ -272,6 +277,7 @@
   "Print": "Stampa",
   "PrintSizeCm": "Dimensioni di stampa (cm)",
   "PrintSizeIn": "Dimensioni di stampa (in)",
+  "Printer": "Stampante",
   "Quality": "Qualità",
   "Random": "Casuale",
   "RawCamera": "Fotocamera Raw",
@@ -299,6 +305,7 @@
   "Save": "Salva",
   "SaveAs": "Salva come",
   "SavingFileFailed": "Salvataggio del file fallito",
+  "Scale": "Scala",
   "ScrollAndRotate": "Scorrere e ruotare",
   "ScrollDirection": "Direzione dello scorrimento",
   "ScrollDown": "Scorri verso il basso",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Alternare il ciclo",
   "ToggleScroll": "Attiva/disattiva scorrimento",
   "ToggleTaskbarProgress": "Mostra progresso sulla barra delle applicazioni",
+  "Top": "Superiore",
   "UnableToRender": "Impossibile renderizzare l'immagine",
   "Unassociate": "Dissocia",
   "Uncalibrated": "Non calibrato",

+ 8 - 0
src/PicView.Core/Config/Languages/ja.json

@@ -30,6 +30,7 @@
   "BitDepth": "ビット深度",
   "BlackAndWhite": "白黒",
   "Blur": "ぼかし",
+  "Bottom": "下",
   "BottomGalleryItemSize": "下部ギャラリーのサムネイルのサイズ",
   "BottomGalleryThumbnailStretch": "下部ギャラリーのサムネイルを伸縮",
   "Brightness": "輝度",
@@ -53,6 +54,7 @@
   "CloseGallery": "ギャラリーを閉じる",
   "CloseWindowPrompt": "ウィンドウを閉じますか?",
   "CloudyWeather": "曇天",
+  "Color": "色",
   "ColorPickerTool": "カラーピッカーツール",
   "ColorPickerToolTooltip": "画像から色を選択",
   "ColorRepresentation": "色彩表現",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "base64 に変換",
   "CoolWhiteFluorescent": "白色蛍光灯",
   "CopiedImage": "画像をクリップボードにコピーしました",
+  "Copies": "部数",
   "Copy": "コピー",
   "CopyFile": "ファイルをコピー",
   "CopyImage": "画像をコピー",
@@ -204,6 +207,7 @@
   "Lossy": "非可逆",
   "Low": "低",
   "Manual": "マニュアル",
+  "Margins": "余白 (mm)",
   "MaxAperture": "最大絞り",
   "Maximize": "最大化",
   "MegaPixels": "メガピクセル",
@@ -254,6 +258,7 @@
   "Orientation": "画像の向き",
   "OutputFolder": "出力フォルダー",
   "Pan": "パン",
+  "PaperSize": "用紙サイズ",
   "PasswordArchive": "パスワード保護されたアーカイブはサポートされていません",
   "PasteImageFromClipholder": "クリップホルダーから画像を貼り付け",
   "PencilSketch": "鉛筆スケッチ",
@@ -272,6 +277,7 @@
   "Print": "印刷",
   "PrintSizeCm": "印刷サイズ (cm)",
   "PrintSizeIn": "印刷サイズ (in)",
+  "Printer": "プリンター",
   "Quality": "品質",
   "Random": "ランダム",
   "RawCamera": "RAWカメラ",
@@ -299,6 +305,7 @@
   "Save": "保存",
   "SaveAs": "名前を付けて保存",
   "SavingFileFailed": "ファイルの保存に失敗しました",
+  "Scale": "拡大縮小",
   "ScrollAndRotate": "スクロールと回転",
   "ScrollDirection": "スクロール方向",
   "ScrollDown": "下にスクロール",
@@ -373,6 +380,7 @@
   "ToggleLooping": "ループの切り替え",
   "ToggleScroll": "スクロールの切り替え",
   "ToggleTaskbarProgress": "タスクバーへ進行状況を表示",
+  "Top": "上",
   "UnableToRender": "画像をレンダリングできません",
   "Unassociate": "関連付け解除",
   "Uncalibrated": "未校正",

+ 8 - 0
src/PicView.Core/Config/Languages/ko.json

@@ -30,6 +30,7 @@
   "BitDepth": "비트 깊이",
   "BlackAndWhite": "흑백",
   "Blur": "흐림",
+  "Bottom": "하단",
   "BottomGalleryItemSize": "하단 갤러리의 썸네일 크기",
   "BottomGalleryThumbnailStretch": "하단 갤러리의 슬라이드쇼 크기",
   "Brightness": "밝기",
@@ -53,6 +54,7 @@
   "CloseGallery": "갤러리 닫기",
   "CloseWindowPrompt": "창을 닫으시겠습니까?",
   "CloudyWeather": "흐린 날씨",
+  "Color": "색",
   "ColorPickerTool": "색 선택 도구",
   "ColorPickerToolTooltip": "이미지에서 색 선택",
   "ColorRepresentation": "색상 표현",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "base64로 변환",
   "CoolWhiteFluorescent": "차가운 흰색 형광등",
   "CopiedImage": "클립보드에 이미지 복사",
+  "Copies": "부수",
   "Copy": "복사",
   "CopyFile": "파일 복사",
   "CopyImage": "이미지 복사",
@@ -204,6 +207,7 @@
   "Lossy": "손실",
   "Low": "낮음",
   "Manual": "수동",
+  "Margins": "여백 (mm)",
   "MaxAperture": "최대 조리개",
   "Maximize": "최대화",
   "MegaPixels": "메가픽셀",
@@ -254,6 +258,7 @@
   "Orientation": "방향",
   "OutputFolder": "출력 폴더",
   "Pan": "팬",
+  "PaperSize": "용지 크기",
   "PasswordArchive": "암호로 보호된 압축파일은 지원되지 않습니다",
   "PasteImageFromClipholder": "클립 홀더에서 이미지 붙여넣기",
   "PencilSketch": "연필 스케치",
@@ -272,6 +277,7 @@
   "Print": "인쇄",
   "PrintSizeCm": "인쇄 크기 (cm)",
   "PrintSizeIn": "인쇄 크기 (in)",
+  "Printer": "프린터",
   "Quality": "품질",
   "Random": "무작위",
   "RawCamera": "RAW 카메라",
@@ -299,6 +305,7 @@
   "Save": "저장",
   "SaveAs": "다른 이름으로 저장",
   "SavingFileFailed": "파일 저장 실패",
+  "Scale": "배율",
   "ScrollAndRotate": "스크롤 및 회전",
   "ScrollDirection": "스크롤 방향",
   "ScrollDown": "아래로 스크롤",
@@ -373,6 +380,7 @@
   "ToggleLooping": "순환 전환",
   "ToggleScroll": "스크롤 전환",
   "ToggleTaskbarProgress": "작업 표시줄 진행률 표시",
+  "Top": "상단",
   "UnableToRender": "이미지를 렌더링할 수 없습니다",
   "Unassociate": "연결 해제",
   "Uncalibrated": "보정되지 않음",

+ 8 - 0
src/PicView.Core/Config/Languages/nl.json

@@ -30,6 +30,7 @@
   "BitDepth": "Bitdiepte",
   "BlackAndWhite": "Zwart & Wit",
   "Blur": "Vervagen",
+  "Bottom": "Onderkant",
   "BottomGalleryItemSize": "Grootte van thumbnail in de onderste galerij",
   "BottomGalleryThumbnailStretch": "Miniatuurrekken in de onderste galerij",
   "Brightness": "Helderheid",
@@ -53,6 +54,7 @@
   "CloseGallery": "Galerij sluiten",
   "CloseWindowPrompt": "Wilt u het venster sluiten?",
   "CloudyWeather": "Bewolkt weer",
+  "Color": "Kleur",
   "ColorPickerTool": "Kleurkiezer",
   "ColorPickerToolTooltip": "Kleur kiezen uit afbeelding",
   "ColorRepresentation": "Kleurenrepresentatie",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Geconverteerd naar base64",
   "CoolWhiteFluorescent": "Koel wit fluoriserend",
   "CopiedImage": "Afbeelding gekopieerd naar klembord",
+  "Copies": "Kopieën",
   "Copy": "Kopiëren",
   "CopyFile": "Bestand kopiëren",
   "CopyImage": "Afbeelding kopiëren",
@@ -204,6 +207,7 @@
   "Lossy": "Verliesrijk",
   "Low": "Laag",
   "Manual": "Handmatig",
+  "Margins": "Marges (mm)",
   "MaxAperture": "Maximale diafragma",
   "Maximize": "Maximaliseren",
   "MegaPixels": "megapixels",
@@ -254,6 +258,7 @@
   "Orientation": "Oriëntatie",
   "OutputFolder": "Uitvoermap",
   "Pan": "Pannen",
+  "PaperSize": "Papiere formaat",
   "PasswordArchive": "Wachtwoord beveiligd archief niet ondersteund",
   "PasteImageFromClipholder": "Afbeelding plakken vanuit klembord",
   "PencilSketch": "Potloodschets",
@@ -272,6 +277,7 @@
   "Print": "Afdrukken",
   "PrintSizeCm": "Printgrootte (cm)",
   "PrintSizeIn": "Printgrootte (in)",
+  "Printer": "Printer",
   "Quality": "Kwaliteit",
   "Random": "Willekeurig",
   "RawCamera": "Ruwe camera",
@@ -299,6 +305,7 @@
   "Save": "Opslaan",
   "SaveAs": "Opslaan als",
   "SavingFileFailed": "Bestand opslaan mislukt",
+  "Scale": "Schaal",
   "ScrollAndRotate": "Scrollen en draaien",
   "ScrollDirection": "Scrollrichting",
   "ScrollDown": "Scroll omlaag",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Lussen wisselen",
   "ToggleScroll": "Scroll wisselen",
   "ToggleTaskbarProgress": "Toon taakbalk voortgang",
+  "Top": "Bovenkant",
   "UnableToRender": "Kan afbeelding niet weergeven",
   "Unassociate": "Koppeling ongedaan maken",
   "Uncalibrated": "Niet gekalibreerd",

+ 8 - 0
src/PicView.Core/Config/Languages/pl.json

@@ -30,6 +30,7 @@
   "BitDepth": "Bitów głębkości koloru",
   "BlackAndWhite": "Czarny i Biały",
   "Blur": "Rozmycie",
+  "Bottom": "Dół",
   "BottomGalleryItemSize": "Liczba elementów na dole galerii",
   "BottomGalleryThumbnailStretch": "Prześrodkuj miniatury na dole galerii",
   "Brightness": "Jasność",
@@ -53,6 +54,7 @@
   "CloseGallery": "Zamknij galerię",
   "CloseWindowPrompt": "Czy chcesz zamknąć okno?",
   "CloudyWeather": "Pochmurno",
+  "Color": "Kolor",
   "ColorPickerTool": "Narzędzie wyboru koloru",
   "ColorPickerToolTooltip": "Wybierz kolor ze zdjęcia",
   "ColorRepresentation": "Reprezentacja kolorów",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Zamieniono na Base64",
   "CoolWhiteFluorescent": "Zimny biały - świetlówka",
   "CopiedImage": "Obraz skopiowany do schowka",
+  "Copies": "Kopie",
   "Copy": "Kopiuj",
   "CopyFile": "Kopiuj plik",
   "CopyImage": "Skopiuj obraz",
@@ -204,6 +207,7 @@
   "Lossy": "Stratna",
   "Low": "Niski",
   "Manual": "Ręczny",
+  "Margins": "Marginesy (mm)",
   "MaxAperture": "Maksymalna przysłona",
   "Maximize": "Maksymalizuj",
   "MegaPixels": "megapikseli",
@@ -254,6 +258,7 @@
   "Orientation": "Orientacja",
   "OutputFolder": "Folder wyjściowy",
   "Pan": "Pochyl",
+  "PaperSize": "Rozmiar papieru",
   "PasswordArchive": "Archiwa chronione hasłem nie są wspierane",
   "PasteImageFromClipholder": "Wklej zdjęcie ze schowka",
   "PencilSketch": "Szkic ołówkiem",
@@ -272,6 +277,7 @@
   "Print": "Drukuj",
   "PrintSizeCm": "Rozmiar wydruku (cm)",
   "PrintSizeIn": "Rozmiar wydruku (cale)",
+  "Printer": "Drukarka",
   "Quality": "Jakość",
   "Random": "Losowo",
   "RawCamera": "Surowe zdjęcia",
@@ -299,6 +305,7 @@
   "Save": "Zapisz",
   "SaveAs": "Zapisz jako",
   "SavingFileFailed": "Zapis pliku nie powiódł się",
+  "Scale": "Skala",
   "ScrollAndRotate": "Przewijaj i obracaj",
   "ScrollDirection": "Kierunek przewijania",
   "ScrollDown": "Przewiń w dół",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Włącz zapętlenie",
   "ToggleScroll": "Włącz scroll",
   "ToggleTaskbarProgress": "Wyświetl postęp na pasku zadań",
+  "Top": "Góra",
   "UnableToRender": "Nie można wyświetlić obrazu",
   "Unassociate": "Rozłącz",
   "Uncalibrated": "Niekalibrowany",

+ 8 - 0
src/PicView.Core/Config/Languages/pt-br.json

@@ -30,6 +30,7 @@
   "BitDepth": "Profundidade de bits",
   "BlackAndWhite": "Preto e branco",
   "Blur": "Desfoque",
+  "Bottom": "Inferior",
   "BottomGalleryItemSize": "Tamanho das miniaturas na galeria inferior",
   "BottomGalleryThumbnailStretch": "Extensão de miniaturas na galeria inferior",
   "Brightness": "Luminosidade",
@@ -53,6 +54,7 @@
   "CloseGallery": "Fechar galeria",
   "CloseWindowPrompt": "Pencereyi kapatmak istiyor musunuz?",
   "CloudyWeather": "Nublado",
+  "Color": "Cor",
   "ColorPickerTool": "Ferramenta de seleção de cores",
   "ColorPickerToolTooltip": "Escolha a cor da imagem",
   "ColorRepresentation": "Representação de cores",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Convertido para base64",
   "CoolWhiteFluorescent": "Branco fluorescente frio",
   "CopiedImage": "Imagem copiada para a área de transferência",
+  "Copies": "Cópias",
   "Copy": "Copiar",
   "CopyFile": "Copiar arquivo",
   "CopyImage": "Copiar imagem",
@@ -204,6 +207,7 @@
   "Lossy": "Com perdas",
   "Low": "Baixo",
   "Manual": "Manual",
+  "Margins": "Margens (mm)",
   "MaxAperture": "Abertura máxima",
   "Maximize": "Maximizar",
   "MegaPixels": "megapixels",
@@ -254,6 +258,7 @@
   "Orientation": "Orientação",
   "OutputFolder": "Pasta de saída",
   "Pan": "Panorama",
+  "PaperSize": "Tamanho de papel",
   "PasswordArchive": "Não há suporte para arquivo protegido por senha",
   "PasteImageFromClipholder": "Colar imagem",
   "PencilSketch": "Esboço a lápis",
@@ -272,6 +277,7 @@
   "Print": "Imprimir",
   "PrintSizeCm": "Tamanho da impressão (cm)",
   "PrintSizeIn": "Tamanho da impressão (in)",
+  "Printer": "Impressora",
   "Quality": "Qualidade",
   "Random": "Aleatório",
   "RawCamera": "Surowe zdjęcia",
@@ -299,6 +305,7 @@
   "Save": "Salvar",
   "SaveAs": "Salvar como",
   "SavingFileFailed": "Falha ao salvar o arquivo",
+  "Scale": "Escala",
   "ScrollAndRotate": "Rolar e girar",
   "ScrollDirection": "Direção da rolagem",
   "ScrollDown": "Rolar para baixo",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Alternar a repetição de imagens",
   "ToggleScroll": "Alternar a rolagem",
   "ToggleTaskbarProgress": "Exibir o progresso na barra de tarefas",
+  "Top": "Superior",
   "UnableToRender": "Não foi possível renderizar a imagem",
   "Unassociate": "Desassociar",
   "Uncalibrated": "Não calibrado",

+ 8 - 0
src/PicView.Core/Config/Languages/ro.json

@@ -30,6 +30,7 @@
   "BitDepth": "Adâncimea biților",
   "BlackAndWhite": "Negru și alb",
   "Blur": "Estompare",
+  "Bottom": "Jos",
   "BottomGalleryItemSize": "Elemente galerie inferioară",
   "BottomGalleryThumbnailStretch": "Întinderea miniaturilor galeriei de jos",
   "Brightness": "Luminozitate",
@@ -53,6 +54,7 @@
   "CloseGallery": "Închide galeria",
   "CloseWindowPrompt": "Doriți să închideți fereastra?",
   "CloudyWeather": "Vreme înnorată",
+  "Color": "Culoare",
   "ColorPickerTool": "Selector de culoare",
   "ColorPickerToolTooltip": "Alegere culoare din imagine",
   "ColorRepresentation": "Reprezentare color",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "CConvertit în base64",
   "CoolWhiteFluorescent": "Fluorescent alb rece",
   "CopiedImage": "Imagine copiată în memoria temporară",
+  "Copies": "Copii",
   "Copy": "Copiere",
   "CopyFile": "Copiere fișier",
   "CopyImage": "Copiere imagine",
@@ -204,6 +207,7 @@
   "Lossy": "Cu pierderi",
   "Low": "Scăzut",
   "Manual": "Manual",
+  "Margins": "Margini (mm)",
   "MaxAperture": "Diafragmă maximă",
   "Maximize": "Maximizare",
   "MegaPixels": "megapixeli",
@@ -254,6 +258,7 @@
   "Orientation": "Orientare",
   "OutputFolder": "Dosar de ieșire",
   "Pan": "Panoramare",
+  "PaperSize": "Dimensiune hârtie",
   "PasswordArchive": "Arhiva protejată cu parolă nu este acceptată",
   "PasteImageFromClipholder": "Lipire imagine din memoria temporară",
   "PencilSketch": "Schiță cu creionul",
@@ -272,6 +277,7 @@
   "Print": "Imprimare",
   "PrintSizeCm": "Dimensiune imprimare (cm)",
   "PrintSizeIn": "Dimensiune imprimare (in)",
+  "Printer": "Imprimantă",
   "Quality": "Calitate",
   "Random": "Aleatoriu",
   "RawCamera": "Cameră Raw",
@@ -299,6 +305,7 @@
   "Save": "Salvare",
   "SaveAs": "Salvează ca",
   "SavingFileFailed": "Salvarea fișierului a eșuat",
+  "Scale": "Scară",
   "ScrollAndRotate": "Derulați și rotiți",
   "ScrollDirection": "Direcție de defilare",
   "ScrollDown": "Derulează în jos",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Comutare repetare",
   "ToggleScroll": "Comutare defilare",
   "ToggleTaskbarProgress": "Afișează progresul în bara de activități",
+  "Top": "Sus",
   "UnableToRender": "Nu se poate reda imaginea",
   "Unassociate": "Dezasociază",
   "Uncalibrated": "Necalibrat",

+ 8 - 0
src/PicView.Core/Config/Languages/ru.json

@@ -30,6 +30,7 @@
   "BitDepth": "Битовая глубина",
   "BlackAndWhite": "Черно-белый",
   "Blur": "Размытие",
+  "Bottom": "Низ",
   "BottomGalleryItemSize": "Количество элементов нижней галереи",
   "BottomGalleryThumbnailStretch": "Растягивание миниатюр в нижней галерее",
   "Brightness": "Яркость",
@@ -53,6 +54,7 @@
   "CloseGallery": "Закрыть галерею",
   "CloseWindowPrompt": "Вы хотите закрыть окно?",
   "CloudyWeather": "Облачная погода",
+  "Color": "Цвет",
   "ColorPickerTool": "Инструмент выбора цвета",
   "ColorPickerToolTooltip": "Выберите цвет из изображения",
   "ColorRepresentation": "Цветовое представление",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Преобразовано в base64",
   "CoolWhiteFluorescent": "Холодный белый флуоресцентный",
   "CopiedImage": "Изображение скопировано в буфер обмена",
+  "Copies": "Копии",
   "Copy": "Копировать",
   "CopyFile": "Копировать файл",
   "CopyImage": "Копировать изображение",
@@ -204,6 +207,7 @@
   "Lossy": "Потеря",
   "Low": "Низкий",
   "Manual": "Ручной",
+  "Margins": "Поля (мм)",
   "MaxAperture": "Максимальная диафрагма",
   "Maximize": "Развернуть",
   "MegaPixels": "мегапикселей",
@@ -254,6 +258,7 @@
   "Orientation": "Ориентация",
   "OutputFolder": "Папки вывода",
   "Pan": "Панорамировать",
+  "PaperSize": "Размер бумаги",
   "PasswordArchive": "Архив, защищенный паролем, не поддерживается",
   "PasteImageFromClipholder": "Вставить изображение из буфера обмена",
   "PencilSketch": "Карандашный набросок",
@@ -272,6 +277,7 @@
   "Print": "Распечатать",
   "PrintSizeCm": "Размер печати (cm)",
   "PrintSizeIn": "Размер печати (in)",
+  "Printer": "Принтер",
   "Quality": "Качественный",
   "Random": "Случайно",
   "RawCamera": "Raw камера",
@@ -299,6 +305,7 @@
   "Save": "Сохранить",
   "SaveAs": "Сохранить как",
   "SavingFileFailed": "Ошибка сохранения файла",
+  "Scale": "Масштаб",
   "ScrollAndRotate": "Прокрутка и вращение",
   "ScrollDirection": "Направление прокрутки",
   "ScrollDown": "Прокрутить вниз",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Переключить цикл",
   "ToggleScroll": "Переключить прокрутку",
   "ToggleTaskbarProgress": "Отображение прогресса на панели задач",
+  "Top": "Верх",
   "UnableToRender": "Невозможно отобразить изображение",
   "Unassociate": "Отменить ассоциацию",
   "Uncalibrated": "Некалиброванный",

+ 8 - 0
src/PicView.Core/Config/Languages/sr.json

@@ -30,6 +30,7 @@
   "BitDepth": "Дубина бита",
   "BlackAndWhite": "Црно-бело",
   "Blur": "Замагљивање",
+  "Bottom": "Donji",
   "BottomGalleryItemSize": "Величина сличица у доњој галерији",
   "BottomGalleryThumbnailStretch": "Истезање сличица у доњој галерији",
   "Brightness": "Осветљеност",
@@ -53,6 +54,7 @@
   "CloseGallery": "Затвори галерију",
   "CloseWindowPrompt": "Да ли затворити прозор?",
   "CloudyWeather": "Облачно време",
+  "Color": "Boja",
   "ColorPickerTool": "Алат за бирање боје",
   "ColorPickerToolTooltip": "Изабери боју са слике",
   "ColorRepresentation": "Представљање боје",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Конвертовано у base64",
   "CoolWhiteFluorescent": "Хладна бела флуоресцентна",
   "CopiedImage": "Копирана слика у клипборд",
+  "Copies": "Kopije",
   "Copy": "Копирај",
   "CopyFile": "Копирај фајл",
   "CopyImage": "Копирај слику",
@@ -204,6 +207,7 @@
   "Lossy": "Са губицима",
   "Low": "Ниско",
   "Manual": "Ручно",
+  "Margins": "Margine (мм)",
   "MaxAperture": "Максимални отвор",
   "Maximize": "Максимизирај",
   "MegaPixels": "мегапиксели",
@@ -254,6 +258,7 @@
   "Orientation": "Оријентација",
   "OutputFolder": "Излазни фолдер",
   "Pan": "Померај",
+  "PaperSize": "Veličina papira",
   "PasswordArchive": "Архива заштићена лозинком није подржана",
   "PasteImageFromClipholder": "Залепи слику из клипборда",
   "PencilSketch": "Оловка скица",
@@ -272,6 +277,7 @@
   "Print": "Штампај",
   "PrintSizeCm": "Величина штампе (цм)",
   "PrintSizeIn": "Величина штампе (ин)",
+  "Printer": "Принтер",
   "Quality": "Квалитет",
   "Random": "Насумично",
   "RawCamera": "Рав камера",
@@ -299,6 +305,7 @@
   "Save": "Сачувај",
   "SaveAs": "Сачувај као",
   "SavingFileFailed": "Чување фајла није успело",
+  "Scale": "Skala",
   "ScrollAndRotate": "Скролуј и ротирај",
   "ScrollDirection": "Правац скроловања",
   "ScrollDown": "Скролуј доле",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Промени понављање",
   "ToggleScroll": "Промени скроловање",
   "ToggleTaskbarProgress": "Прикажи напредовање на траци задатака",
+  "Top": "Gornji",
   "UnableToRender": "Не могу да прикажем слику",
   "Unassociate": "Уклони асоцијацију",
   "Uncalibrated": "Некалибрисано",

+ 8 - 0
src/PicView.Core/Config/Languages/sv.json

@@ -30,6 +30,7 @@
   "BitDepth": "Bitdjup",
   "BlackAndWhite": "Svart/vit",
   "Blur": "Oskärpa",
+  "Bottom": "Botten",
   "BottomGalleryItemSize": "Storlek på tumnaglar i nedre galleriet",
   "BottomGalleryThumbnailStretch": "Sträck tumnagnaglar i nedre galleriet",
   "Brightness": "Ljusstyrka",
@@ -53,6 +54,7 @@
   "CloseGallery": "Stäng galleriet",
   "CloseWindowPrompt": "Vill du stänga fönstret?",
   "CloudyWeather": "Molnigt",
+  "Color": "Färg",
   "ColorPickerTool": "Färgprov",
   "ColorPickerToolTooltip": "Ta färgprov i bilden",
   "ColorRepresentation": "Färgrepresentation",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Konverterad till base64",
   "CoolWhiteFluorescent": "Lysrör kallvitt",
   "CopiedImage": "Kopierade bilden till urklipp",
+  "Copies": "Kopior",
   "Copy": "Kopiera",
   "CopyFile": "Kopiera fil",
   "CopyImage": "Kopiera bild",
@@ -204,6 +207,7 @@
   "Lossy": "Förstörande",
   "Low": "Låg",
   "Manual": "Manuell",
+  "Margins": "Marginaler (mm)",
   "MaxAperture": "Största bländare",
   "Maximize": "Maximera",
   "MegaPixels": "megapixel",
@@ -254,6 +258,7 @@
   "Orientation": "Orientering",
   "OutputFolder": "Destinationsmapp",
   "Pan": "Panorera",
+  "PaperSize": "Pappersstorlek",
   "PasswordArchive": "Lösenordsskyddade arkiv stöds inte",
   "PasteImageFromClipholder": "Klista in bild",
   "PencilSketch": "Blyertsskiss",
@@ -272,6 +277,7 @@
   "Print": "Skriv ut",
   "PrintSizeCm": "Utskriftsstorlek (cm)",
   "PrintSizeIn": "Utskriftsstorlek (tum)",
+  "Printer": "Skrivare",
   "Quality": "Kvalitet",
   "Random": "Slumpad",
   "RawCamera": "Rå kamera",
@@ -299,6 +305,7 @@
   "Save": "Spara",
   "SaveAs": "Spara som",
   "SavingFileFailed": "Spara bild misslyckades",
+  "Scale": "Skala",
   "ScrollAndRotate": "Rulla och rotera",
   "ScrollDirection": "Rullningsriktning",
   "ScrollDown": "Rulla ner",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Slinga av/på",
   "ToggleScroll": "Rullning av/på",
   "ToggleTaskbarProgress": "Visa framstegsstapel",
+  "Top": "Topp",
   "UnableToRender": "Kan inte skapa bilden",
   "Unassociate": "Avassociera",
   "Uncalibrated": "Okalilbrerad",

+ 8 - 0
src/PicView.Core/Config/Languages/tr.json

@@ -30,6 +30,7 @@
   "BitDepth": "Bit derinliği",
   "BlackAndWhite": "Siyah Beyaz",
   "Blur": "Bulanıklaştırma",
+  "Bottom": "Alt",
   "BottomGalleryItemSize": "Alt galerideki küçük resimlerin boyutu",
   "BottomGalleryThumbnailStretch": "Alt galeride küçük resim esnemesi",
   "Brightness": "Parlaklık",
@@ -53,6 +54,7 @@
   "CloseGallery": "Galeriyi kapat",
   "CloseWindowPrompt": "Pencereyi kapatmak istiyor musunuz?",
   "CloudyWeather": "Bulutlu hava",
+  "Color": "Renk",
   "ColorPickerTool": "Renk Seçme Aracı",
   "ColorPickerToolTooltip": "Görüntüden renk seç",
   "ColorRepresentation": "Renk gösterimi",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "Base64'e dönüştürüldü",
   "CoolWhiteFluorescent": "Soğuk beyaz floresan",
   "CopiedImage": "Görüntü panoya kopyalandı",
+  "Copies": "Kopya",
   "Copy": "Kopyala",
   "CopyFile": "Dosyayı kopyala",
   "CopyImage": "Görüntüyü kopyala",
@@ -204,6 +207,7 @@
   "Lossy": "Kayıplı",
   "Low": "Düşük",
   "Manual": "Manuel",
+  "Margins": "Kenar boşlukları (mm)",
   "MaxAperture": "En büyük diyafram açıklığı",
   "Maximize": "Büyüt",
   "MegaPixels": "megapiksel",
@@ -254,6 +258,7 @@
   "Orientation": "Yönlendirme",
   "OutputFolder": "Çıktı klasörü",
   "Pan": "Panorama",
+  "PaperSize": "Kağıt Boyutu",
   "PasswordArchive": "Şifreli arşiv desteklenmiyor",
   "PasteImageFromClipholder": "Panodaki görüntüyü yapıştır",
   "PencilSketch": "Kurşun Kalem Çizimi",
@@ -272,6 +277,7 @@
   "Print": "Yazdır",
   "PrintSizeCm": "Yazdırma boyutu (cm)",
   "PrintSizeIn": "Yazdırma boyutu (inç)",
+  "Printer": "Yazıcı",
   "Quality": "Kalite",
   "Random": "Rastgele",
   "RawCamera": "Raw Kamera",
@@ -299,6 +305,7 @@
   "Save": "Kaydet",
   "SaveAs": "Farklı kaydet",
   "SavingFileFailed": "Dosya kaydedilemedi",
+  "Scale": "Ölçek",
   "ScrollAndRotate": "Kaydır ve döndür",
   "ScrollDirection": "Kaydırma yönü",
   "ScrollDown": "Aşağı kaydır",
@@ -373,6 +380,7 @@
   "ToggleLooping": "Döngüyü aç / kapat",
   "ToggleScroll": "Kaydırmayı aç / kapat",
   "ToggleTaskbarProgress": "Görev çubuğu ilerlemesini görüntüle",
+  "Top": "Üst",
   "UnableToRender": "Görüntü işlenemiyor",
   "Unassociate": "İlişkilendirmeyi kaldır",
   "Uncalibrated": "Kalibre edilmemiş",

+ 8 - 0
src/PicView.Core/Config/Languages/zh-CN.json

@@ -30,6 +30,7 @@
   "BitDepth": "位深",
   "BlackAndWhite": "黑白",
   "Blur": "模糊",
+  "Bottom": "下边",
   "BottomGalleryItemSize": "底部图库项目",
   "BottomGalleryThumbnailStretch": "缩略图拉伸在底部图库",
   "Brightness": "亮度",
@@ -53,6 +54,7 @@
   "CloseGallery": "关闭相册",
   "CloseWindowPrompt": "您想关闭窗口吗?",
   "CloudyWeather": "多云",
+  "Color": "颜色",
   "ColorPickerTool": "取色工具",
   "ColorPickerToolTooltip": "从图片中选取颜色",
   "ColorRepresentation": "颜色表示",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "已复制为 base64",
   "CoolWhiteFluorescent": "冷白荧光",
   "CopiedImage": "已将图像复制至剪贴板",
+  "Copies": "份数",
   "Copy": "复制",
   "CopyFile": "复制文件",
   "CopyImage": "复制图像",
@@ -204,6 +207,7 @@
   "Lossy": "有损",
   "Low": "低",
   "Manual": "手动",
+  "Margins": "边距 (毫米)",
   "MaxAperture": "最大光圈",
   "Maximize": "最大化",
   "MegaPixels": "mp",
@@ -254,6 +258,7 @@
   "Orientation": "方向",
   "OutputFolder": "输出文件夹",
   "Pan": "平移",
+  "PaperSize": "纸张大小",
   "PasswordArchive": "暂不支持带密码的压缩文件",
   "PasteImageFromClipholder": "从剪贴板中粘贴图片",
   "PencilSketch": "铅笔素描",
@@ -272,6 +277,7 @@
   "Print": "打印",
   "PrintSizeCm": "打印大小(厘米)",
   "PrintSizeIn": "打印大小(英尺)",
+  "Printer": "打印机",
   "Quality": "质量",
   "Random": "随机",
   "RawCamera": "Raw相机",
@@ -299,6 +305,7 @@
   "Save": "保存",
   "SaveAs": "另存为",
   "SavingFileFailed": "文件保存失败",
+  "Scale": "比例",
   "ScrollAndRotate": "滚动和旋转",
   "ScrollDirection": "滚动方向",
   "ScrollDown": "向下滑动",
@@ -373,6 +380,7 @@
   "ToggleLooping": "切换循环",
   "ToggleScroll": "切换滚动",
   "ToggleTaskbarProgress": "显示任务栏进度",
+  "Top": "上边",
   "UnableToRender": "无法渲染图像",
   "Unassociate": "取消关联",
   "Uncalibrated": "未校准",

+ 8 - 0
src/PicView.Core/Config/Languages/zh-TW.json

@@ -30,6 +30,7 @@
   "BitDepth": "色深",
   "BlackAndWhite": "黑白",
   "Blur": "模糊",
+  "Bottom": "下方",
   "BottomGalleryItemSize": "底部圖庫項目",
   "BottomGalleryThumbnailStretch": "圖庫項目縮放",
   "Brightness": "亮度",
@@ -53,6 +54,7 @@
   "CloseGallery": "關閉相簿",
   "CloseWindowPrompt": "您想關閉窗口嗎?",
   "CloudyWeather": "多雲",
+  "Color": "顏色",
   "ColorPickerTool": "取色工具",
   "ColorPickerToolTooltip": "從圖片中選取顏色",
   "ColorRepresentation": "色彩表示",
@@ -66,6 +68,7 @@
   "ConvertedToBase64": "已複製為 base64",
   "CoolWhiteFluorescent": "冷白螢光",
   "CopiedImage": "已將影像複製至剪貼簿",
+  "Copies": "份數",
   "Copy": "複製",
   "CopyFile": "複製檔案",
   "CopyImage": "複製影像",
@@ -204,6 +207,7 @@
   "Lossy": "有損",
   "Low": "低",
   "Manual": "手動",
+  "Margins": "邊界 (毫米)",
   "MaxAperture": "最大光圈",
   "Maximize": "最大化",
   "MegaPixels": "百萬像素",
@@ -254,6 +258,7 @@
   "Orientation": "方向",
   "OutputFolder": "匯出目錄",
   "Pan": "平移",
+  "PaperSize": "紙張大小",
   "PasswordArchive": "暫不支援加密的壓縮檔案",
   "PasteImageFromClipholder": "從剪貼簿中貼上圖片",
   "PencilSketch": "鉛筆素描",
@@ -272,6 +277,7 @@
   "Print": "列印",
   "PrintSizeCm": "列印大小(公分)",
   "PrintSizeIn": "列印大小(英吋)",
+  "Printer": "印表機",
   "Quality": "品質",
   "Random": "隨機",
   "RawCamera": "Raw 相機",
@@ -299,6 +305,7 @@
   "Save": "儲存",
   "SaveAs": "另存新檔",
   "SavingFileFailed": "檔案儲存失敗",
+  "Scale": "比例",
   "ScrollAndRotate": "捲動和旋轉",
   "ScrollDirection": "滑鼠滾輪方向",
   "ScrollDown": "向下滑動",
@@ -373,6 +380,7 @@
   "ToggleLooping": "切換迴圈",
   "ToggleScroll": "切換滾動",
   "ToggleTaskbarProgress": "顯示工作列進度",
+  "Top": "上方",
   "UnableToRender": "无法渲染图像",
   "Unassociate": "取消關聯",
   "Uncalibrated": "未校準",

+ 6 - 0
src/PicView.Core/Config/SettingsConfiguration.cs

@@ -6,4 +6,10 @@ public class SettingsConfiguration() : ConfigFile("UserSettings.json")
 {
     public const double CurrentSettingsVersion = 1.7;
 
+}
+
+public class GlobalSettingsConfiguration() : ConfigFile("GlobalSettings.json")
+{
+    public const double CurrentSettingsVersion = 1.7;
+
 }

+ 93 - 16
src/PicView.Core/Config/SettingsManager.cs

@@ -41,9 +41,18 @@ public static class SettingsManager
     /// <see cref="SettingsManager.SaveSettingsAsync"/>.
     /// </remarks>
     public static AppSettings? Settings { get; private set; }
-    
+
     public static SettingsConfiguration? Configuration { get; private set; }
 
+    /// <summary>
+    /// Global Configuration Support
+    /// </summary>
+    /// <remarks>
+    /// Overrides any UserSettings with GlobalSettings if they are set
+    /// </remarks>
+    public static GlobalSettingsConfiguration? GlobalConfig { get; private set; }
+    public static AppSettings? GlobalSettings { get; private set; }
+
     /// <summary>
     /// Loads application settings asynchronously from a file or initializes them to default if loading fails.
     /// </summary>
@@ -55,26 +64,42 @@ public static class SettingsManager
     {
         try
         {
-            Configuration ??= new SettingsConfiguration();
-            var path = ConfigFileManager.ResolveDefaultConfigPath(Configuration);
-            if (!string.IsNullOrEmpty(path))
+            // Load global config (read-only, Program Path)
+            GlobalConfig ??= new GlobalSettingsConfiguration();
+            string globalPath = GlobalConfig.LocalConfigPath;
+            if (File.Exists(globalPath))
             {
-                Configuration.CorrectPath = path;
-                var jsonString = await File.ReadAllTextAsync(path).ConfigureAwait(false);
-
-                if (JsonSerializer.Deserialize(
-                        jsonString, typeof(AppSettings), SettingsGenerationContext.Default) is not AppSettings settings)
+                await using var globalStream = File.OpenRead(globalPath);
+                if (globalStream.Length > 0)
                 {
-                    SetDefaults();
-                    return false;
+                    GlobalSettings = await JsonSerializer.DeserializeAsync<AppSettings>(
+                        globalStream, SettingsGenerationContext.Default.AppSettings).ConfigureAwait(false);
                 }
+            }
+
+            // Load user config (User Profile or Program Path)
+            Configuration ??= new SettingsConfiguration();
+            var userPath = ConfigFileManager.ResolveDefaultConfigPath(Configuration);
+            Configuration.CorrectPath = userPath;
 
-                Settings = EnsureSettingsIfNeeded(settings);
-                return true;
+            if (File.Exists(userPath))
+            {
+                await using var userStream = File.OpenRead(userPath);
+                if (userStream.Length > 0)
+                {
+                    Settings = await JsonSerializer.DeserializeAsync<AppSettings>(
+                        userStream, SettingsGenerationContext.Default.AppSettings).ConfigureAwait(false);
+                }
             }
 
-            SetDefaults();
-            return false;
+            // Fallback to defaults if no user config found
+            Settings ??= GetDefaults();
+
+            // Apply Global Overrides
+            if (GlobalSettings != null)
+                ApplyOverrides(Settings, GlobalSettings);
+
+            return true;
         }
         catch (Exception ex)
         {
@@ -132,7 +157,7 @@ public static class SettingsManager
         {
             return EnsureSettings(settings);
         }
-        
+
         // If navigation settings is null, it is an upgrade from an old version or the config is otherwise invalid
         if (settings.Navigation is null)
         {
@@ -243,4 +268,56 @@ public static class SettingsManager
             }
         }
     }
+    
+    private static void ApplyOverrides(AppSettings target, AppSettings global)
+    {
+        MergeObjects(target, global);
+    }
+
+    /// <summary>
+    /// Recursively merges all non-null properties from source into target.
+    /// Complex nested types (like UIProperties, Theme, etc.) are merged recursively.
+    /// Value types and simple properties are directly overwritten.
+    /// </summary>
+    private static void MergeObjects(object? target, object? source)
+    {
+        if (target == null || source == null)
+            return;
+
+        var targetType = target.GetType();
+        var sourceType = source.GetType();
+
+        foreach (var prop in sourceType.GetProperties())
+        {
+            var sourceValue = prop.GetValue(source);
+            if (sourceValue == null)
+                continue;
+
+            var targetProp = targetType.GetProperty(prop.Name);
+            if (targetProp == null || !targetProp.CanWrite)
+                continue;
+
+            var targetValue = targetProp.GetValue(target);
+
+            // If this is a nested object (class) and not a string, merge recursively
+            if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
+            {
+                if (targetValue == null)
+                {
+                    // If user doesn't have that object at all, copy it fully
+                    targetProp.SetValue(target, sourceValue);
+                }
+                else
+                {
+                    // Recursively merge individual properties
+                    MergeObjects(targetValue, sourceValue);
+                }
+            }
+            else
+            {
+                // Simple value type or string – overwrite directly
+                targetProp.SetValue(target, sourceValue);
+            }
+        }
+    }
 }

+ 8 - 0
src/PicView.Core/Localization/LanguageModel.cs

@@ -40,6 +40,7 @@ public class LanguageModel
     public string? BitDepth { get; set; }
     public string? BlackAndWhite { get; set; }
     public string? Blur { get; set; }
+    public string? Bottom { get; set; }
     public string? BottomGalleryItemSize { get; set; }
     public string? BottomGalleryThumbnailStretch { get; set; }
     public string? Brightness { get; set; }
@@ -63,6 +64,7 @@ public class LanguageModel
     public string? CloseGallery { get; set; }
     public string? CloseWindowPrompt { get; set; }
     public string? CloudyWeather { get; set; }
+    public string? Color { get; set; }
     public string? ColorPickerTool { get; set; }
     public string? ColorPickerToolTooltip { get; set; }
     public string? ColorRepresentation { get; set; }
@@ -75,6 +77,7 @@ public class LanguageModel
     public string? ConvertedToBase64 { get; set; }
     public string? ConvertTo { get; set; }
     public string? CoolWhiteFluorescent { get; set; }
+    public string? Copies { get; set; }
     public string? CopiedImage { get; set; }
     public string? Copy { get; set; }
     public string? CopyFile { get; set; }
@@ -214,6 +217,7 @@ public class LanguageModel
     public string? Lossy { get; set; }
     public string? Low { get; set; }
     public string? Manual { get; set; }
+    public string? Margins { get; set; }
     public string? MaxAperture { get; set; }
     public string? Maximize { get; set; }
     public string? MegaPixels { get; set; }
@@ -264,6 +268,7 @@ public class LanguageModel
     public string? Orientation { get; set; }
     public string? OutputFolder { get; set; }
     public string? Pan { get; set; }
+    public string? PaperSize { get; set; }
     public string? PasswordArchive { get; set; }
     public string? PasteImageFromClipholder { get; set; }
     public string? PencilSketch { get; set; }
@@ -280,6 +285,7 @@ public class LanguageModel
     public string? PrevFolder { get; set; }
     public string? PrevImage { get; set; }
     public string? Print { get; set; }
+    public string? Printer { get; set; }
     public string? PrintSizeCm { get; set; }
     public string? PrintSizeIn { get; set; }
     public string? Quality { get; set; }
@@ -309,6 +315,7 @@ public class LanguageModel
     public string? Save { get; set; }
     public string? SaveAs { get; set; }
     public string? SavingFileFailed { get; set; }
+    public string? Scale { get; set; }
     public string? ScrollAndRotate { get; set; }
     public string? ScrollDirection { get; set; }
     public string? ScrollDown { get; set; }
@@ -383,6 +390,7 @@ public class LanguageModel
     public string? ToggleLooping { get; set; }
     public string? ToggleScroll { get; set; }
     public string? ToggleTaskbarProgress { get; set; }
+    public string? Top { get; set; }
     public string? UnableToRender { get; set; }
     public string? Unassociate { get; set; }
     public string? Uncalibrated { get; set; }

+ 52 - 0
src/PicView.Core/Printing/PrintSettings.cs

@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PicView.Core.Localization;
+using R3;
+
+namespace PicView.Avalonia.Printing
+{
+    public class PrintSettings
+    {
+        public BindableReactiveProperty<string?> ImagePath { get; } = new();
+        public BindableReactiveProperty<string?> PrinterName { get; } = new();
+        public BindableReactiveProperty<string?> PaperSize { get; } = new();
+        public BindableReactiveProperty<int> Orientation { get; } = new((int)Orientations.Portrait);
+        public BindableReactiveProperty<int> ScaleMode { get; } = new((int)ScaleModes.Fit);
+        public BindableReactiveProperty<int> ColorMode { get; } = new((int)ColorModes.Auto);
+        public BindableReactiveProperty<int> Copies { get; } = new(1);
+        public BindableReactiveProperty<int> MarginTop { get; } = new(0);
+        public BindableReactiveProperty<int> MarginBottom { get; } = new(0);
+        public BindableReactiveProperty<int> MarginLeft { get; } = new(0);
+        public BindableReactiveProperty<int> MarginRight { get; } = new(0);
+
+
+        public static int HundredthsInchToMm(int hundredthsInch) => (int)Math.Round(hundredthsInch * 0.254);
+
+        public static int MmToHundredthsInch(double mm) => (int)Math.Round(mm / 0.254);
+
+    }
+
+    public enum ScaleModes
+    {
+        Fit,
+        Fill,
+        Stretch,
+        Center
+    }
+
+    public enum ColorModes
+    {
+        Auto,
+        Color,
+        BlackAndWhite
+    }
+
+    public enum Orientations
+    {
+        Portrait,
+        Landscape
+    }
+}

+ 4 - 2
src/PicView.Core/ViewModels/GlobalSettingsViewModel.cs

@@ -16,8 +16,10 @@ public class GlobalSettingsViewModel
     public BindableReactiveProperty<bool> IsLooping { get; } = new(Settings.UIProperties.Looping);
 
     public BindableReactiveProperty<bool> IsAutoFit { get; } = new(Settings.WindowProperties.AutoFit);
-    
+
     public BindableReactiveProperty<bool> IsFileHistoryEnabled { get; } = new(Settings.Navigation.IsFileHistoryEnabled);
-    
+
     public BindableReactiveProperty<bool> IsShowingTaskbarProgress { get; } = new(Settings.UIProperties.IsTaskbarProgressEnabled);
+    
+    public BindableReactiveProperty<bool> ShowSetAsWallpaper { get; } = new(Settings.UIProperties.ShowSetAsWallpaper);
 }

+ 93 - 0
src/PicView.Core/ViewModels/PrintPreviewViewModel.cs

@@ -0,0 +1,93 @@
+using System.Collections;
+using System.Collections.ObjectModel;
+using PicView.Avalonia.Printing;
+using PicView.Core.Localization;
+using R3;
+
+// ReSharper disable CompareOfFloatsByEqualityOperator
+
+namespace PicView.Core.ViewModels;
+
+public class PrintPreviewViewModel : IDisposable
+{
+    public readonly CompositeDisposable _disposables = new();
+
+    public PrintPreviewViewModel()
+    {
+        ScaleModes.Value = new [] 
+        { 
+            TranslationManager.Translation.Fit, 
+            TranslationManager.Translation.Fill, 
+            TranslationManager.Translation.Stretch, 
+            TranslationManager.Translation.Center 
+        };
+
+        Orientations.Value = new [] 
+        { 
+            TranslationManager.Translation.Portrait, 
+            TranslationManager.Translation.Landscape 
+        };
+
+        ColorModes.Value = new [] 
+        { 
+            TranslationManager.Translation.Auto, 
+            TranslationManager.Translation.Color, 
+            TranslationManager.Translation.BlackAndWhite 
+        };
+
+    }
+
+    #region Bindable Properties
+
+    public BindableReactiveProperty<IEnumerable<string>> Printers { get; } = new();
+    public BindableReactiveProperty<IEnumerable<string>> PaperSizes { get; } = new();
+    public BindableReactiveProperty<IEnumerable<string?>> ScaleModes { get; } = new();
+    public BindableReactiveProperty<IEnumerable<string?>> ColorModes { get; } = new();
+    public BindableReactiveProperty<IEnumerable<string?>> Orientations { get; } = new();
+    public BindableReactiveProperty<PrintSettings> PrintSettings { get; } = new();
+    public BindableReactiveProperty<object?> PreviewImage { get; } = new();
+
+    public BindableReactiveProperty<double> PageWidth { get; } = new();
+    public BindableReactiveProperty<double> PageHeight { get; } = new();
+
+    public BindableReactiveProperty<double> Zoom { get; } = new(1.0);
+
+    public BindableReactiveProperty<bool> IsProcessing { get; } = new(false);
+    public BindableReactiveProperty<double> Opacity { get; } = new(1.0);
+
+    public Object? GrayCache { get; set; }
+
+
+    #endregion
+
+
+    #region Commands
+
+    public ReactiveCommand<Unit> PrintCommand { get; } = new();
+    public ReactiveCommand<Unit> CancelCommand { get; } = new();
+
+    #endregion
+
+    #region Disposal
+
+    public void Dispose()
+    {
+        Disposable.Dispose(_disposables,
+            Printers,
+            PaperSizes,
+            ScaleModes,
+            ColorModes,
+            Orientations,
+            PrintSettings,
+            PreviewImage,
+            PageWidth,
+            PageHeight,
+            Zoom,
+            IsProcessing,
+            Opacity,
+            PrintCommand,
+            CancelCommand);
+    }
+
+    #endregion
+}

+ 24 - 1
src/PicView.Core/ViewModels/TranslationViewModel.cs

@@ -13,7 +13,7 @@ public class TranslationViewModel : IDisposable
     public void UpdateLanguage()
     {
         var t = TranslationManager.Translation;
-        
+
         File.Value = string.Concat(t.File[0].ToString().ToUpper(), t.File.AsSpan(1));
         SelectFile.Value = t.OpenFileDialog;
         OpenLastFile.Value = t.OpenLastFile;
@@ -308,6 +308,17 @@ public class TranslationViewModel : IDisposable
         ShowZoomPercentagePopup.Value = t.ShowZoomPercentagePopup;
         UseAnimatedZoom.Value = t.UseAnimatedZoom;
         WhenDeletingAFile.Value = t.WhenDeletingAFile;
+
+        Printer.Value = t.Printer;
+        PaperSize.Value = t.PaperSize;
+        Scale.Value = t.Scale;
+        Color.Value = t.Color;
+        Copies.Value = t.Copies;
+        Margins.Value = t.Margins;
+        Top.Value = t.Top;
+        Bottom.Value = t.Bottom;
+        Left.Value = t.Left;
+        Right.Value = t.Right;
     }
 
     #region Static Translation Strings
@@ -636,5 +647,17 @@ public class TranslationViewModel : IDisposable
     public BindableReactiveProperty<string?> IsShowingUI { get; } = new();
     public BindableReactiveProperty<string?> IsUsingTouchpad { get; } = new();
 
+
+    public BindableReactiveProperty<string?> Printer { get; } = new();
+    public BindableReactiveProperty<string?> PaperSize { get; } = new();
+    public BindableReactiveProperty<string?> Scale { get; } = new();
+    public BindableReactiveProperty<string?> Color { get; } = new();
+    public BindableReactiveProperty<string?> Copies { get; } = new();
+    public BindableReactiveProperty<string?> Margins { get; } = new();
+    public BindableReactiveProperty<string?> Top { get; } = new();
+    public BindableReactiveProperty<string?> Bottom { get; } = new();
+    public BindableReactiveProperty<string?> Left { get; } = new();
+    public BindableReactiveProperty<string?> Right { get; } = new();
+
     #endregion
 }