mirror of
https://github.com/cyanfish/naps2.git
synced 2024-10-05 20:07:42 +03:00
Gtk: Add printing support
This commit is contained in:
parent
b804a8a7d7
commit
9f6fea02b4
19
NAPS2.Images.Gtk/GtkExtensions.cs
Normal file
19
NAPS2.Images.Gtk/GtkExtensions.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using Gdk;
|
||||
|
||||
namespace NAPS2.Images.Gtk;
|
||||
|
||||
public static class GtkExtensions
|
||||
{
|
||||
public static Pixbuf RenderToPixbuf(this IRenderableImage image)
|
||||
{
|
||||
var gtkImageContext = image.ImageContext as GtkImageContext ??
|
||||
throw new ArgumentException("The provided image does not have a GtkImageContext");
|
||||
return gtkImageContext.RenderToPixbuf(image);
|
||||
}
|
||||
|
||||
public static Pixbuf AsPixbuf(this IMemoryImage image)
|
||||
{
|
||||
var gtkImage = image as GtkImage ?? throw new ArgumentException("Expected a GtkImage", nameof(image));
|
||||
return gtkImage.Pixbuf;
|
||||
}
|
||||
}
|
@ -53,6 +53,11 @@ public class GtkImageContext : ImageContext
|
||||
|
||||
internal LibTiffIo TiffIo => _tiffIo;
|
||||
|
||||
public Pixbuf RenderToPixbuf(IRenderableImage image)
|
||||
{
|
||||
return ((GtkImage) Render(image)).Pixbuf;
|
||||
}
|
||||
|
||||
public override IMemoryImage Create(int width, int height, ImagePixelFormat pixelFormat)
|
||||
{
|
||||
if (pixelFormat == ImagePixelFormat.Unsupported)
|
||||
|
80
NAPS2.Lib.Gtk/ImportExport/GtkScannedImagePrinter.cs
Normal file
80
NAPS2.Lib.Gtk/ImportExport/GtkScannedImagePrinter.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using Gtk;
|
||||
using NAPS2.Images.Gtk;
|
||||
|
||||
namespace NAPS2.ImportExport;
|
||||
|
||||
public class GtkScannedImagePrinter : IScannedImagePrinter
|
||||
{
|
||||
public async Task<bool> PromptToPrint(
|
||||
Eto.Forms.Window parentWindow, IList<ProcessedImage> images, IList<ProcessedImage> selectedImages)
|
||||
{
|
||||
if (!images.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
var printOp = new PrintOperation
|
||||
{
|
||||
NPages = images.Count,
|
||||
UseFullPage = true,
|
||||
HasSelection = selectedImages.Count > 1,
|
||||
SupportSelection = selectedImages.Count > 1
|
||||
};
|
||||
if (selectedImages.Count == 1)
|
||||
{
|
||||
printOp.CurrentPage = images.IndexOf(selectedImages[0]);
|
||||
}
|
||||
var printTarget = images;
|
||||
printOp.BeginPrint += (_, args) =>
|
||||
{
|
||||
if (printOp.PrintSettings.PrintPages == PrintPages.Selection)
|
||||
{
|
||||
printTarget = selectedImages;
|
||||
printOp.NPages = printTarget.Count;
|
||||
}
|
||||
};
|
||||
printOp.DrawPage += (_, args) =>
|
||||
{
|
||||
var image = printTarget[args.PageNr].Render();
|
||||
try
|
||||
{
|
||||
var ctx = args.Context;
|
||||
var cairoCtx = ctx.CairoContext;
|
||||
|
||||
if (Math.Sign(image.Width - image.Height) != Math.Sign(ctx.Width - ctx.Height))
|
||||
{
|
||||
// Flip portrait/landscape to match output
|
||||
image = image.PerformTransform(new RotationTransform(90));
|
||||
}
|
||||
|
||||
// Fit the image into the output rect (centered) while maintaining its aspect ratio
|
||||
var heightBound = image.Width / ctx.Width < image.Height / ctx.Height;
|
||||
var targetWidth = heightBound ? image.Width * ctx.Height / image.Height : ctx.Width;
|
||||
var targetHeight = heightBound ? ctx.Height : image.Height * ctx.Width / image.Width;
|
||||
var targetX = (ctx.Width - targetWidth) / 2;
|
||||
var targetY = (ctx.Height - targetHeight) / 2;
|
||||
cairoCtx.Translate(targetX, targetY);
|
||||
cairoCtx.Scale(targetWidth / image.Width, targetHeight / image.Height);
|
||||
|
||||
Gdk.CairoHelper.SetSourcePixbuf(cairoCtx, image.AsPixbuf(), 0, 0);
|
||||
cairoCtx.Paint();
|
||||
}
|
||||
finally
|
||||
{
|
||||
image.Dispose();
|
||||
}
|
||||
};
|
||||
printOp.EndPrint += (_, args) =>
|
||||
{
|
||||
Log.Event(EventType.Print, new EventParams
|
||||
{
|
||||
Name = MiscResources.Print,
|
||||
Pages = printOp.NPagesToPrint
|
||||
});
|
||||
};
|
||||
var result = printOp.Run(PrintOperationAction.PrintDialog, (Window) parentWindow.ControlObject);
|
||||
return result == PrintOperationResult.Apply;
|
||||
});
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ public class GtkModule : GuiModule
|
||||
base.Load(builder);
|
||||
|
||||
builder.RegisterType<StubNotificationManager>().As<INotificationManager>().SingleInstance();
|
||||
builder.RegisterType<StubScannedImagePrinter>().As<IScannedImagePrinter>();
|
||||
builder.RegisterType<GtkScannedImagePrinter>().As<IScannedImagePrinter>();
|
||||
builder.RegisterType<GtkDarkModeProvider>().As<IDarkModeProvider>();
|
||||
builder.RegisterType<GtkImageContext>().As<ImageContext>();
|
||||
builder.RegisterType<GtkImageContext>().AsSelf();
|
||||
@ -27,14 +27,6 @@ public class GtkModule : GuiModule
|
||||
}
|
||||
}
|
||||
|
||||
public class StubScannedImagePrinter : IScannedImagePrinter
|
||||
{
|
||||
public Task<bool> PromptToPrint(IList<ProcessedImage> images, IList<ProcessedImage> selectedImages)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public class StubNotificationManager : INotificationManager
|
||||
{
|
||||
public void PdfSaved(string path)
|
||||
|
@ -7,14 +7,8 @@ namespace NAPS2.ImportExport;
|
||||
|
||||
public class PrintDocumentPrinter : IScannedImagePrinter
|
||||
{
|
||||
private readonly ImageContext _imageContext;
|
||||
|
||||
public PrintDocumentPrinter(ImageContext imageContext)
|
||||
{
|
||||
_imageContext = imageContext;
|
||||
}
|
||||
|
||||
public async Task<bool> PromptToPrint(IList<ProcessedImage> images, IList<ProcessedImage> selectedImages)
|
||||
public async Task<bool> PromptToPrint(
|
||||
Eto.Forms.Window parentWindow, IList<ProcessedImage> images, IList<ProcessedImage> selectedImages)
|
||||
{
|
||||
if (!images.Any())
|
||||
{
|
||||
@ -22,6 +16,8 @@ public class PrintDocumentPrinter : IScannedImagePrinter
|
||||
}
|
||||
var printDialog = new PrintDialog
|
||||
{
|
||||
// TODO: If we migrate this to WPF we might be able to enable print previews
|
||||
// WinForms has UseEXDialog which will use the modern windows dialog but has no way to populate the preview
|
||||
AllowSelection = selectedImages.Any(),
|
||||
AllowSomePages = true,
|
||||
PrinterSettings =
|
||||
|
@ -466,7 +466,8 @@ public class DesktopController
|
||||
var state = _imageList.CurrentState;
|
||||
using var allImages = _imageList.Images.Select(x => x.GetClonedImage()).ToDisposableList();
|
||||
using var selectedImages = _imageList.Selection.Select(x => x.GetClonedImage()).ToDisposableList();
|
||||
if (await _scannedImagePrinter.PromptToPrint(allImages.InnerList, selectedImages.InnerList))
|
||||
if (await _scannedImagePrinter.PromptToPrint(
|
||||
_desktopFormProvider.DesktopForm, allImages.InnerList, selectedImages.InnerList))
|
||||
{
|
||||
_imageList.SavedState = state;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
using Eto.Forms;
|
||||
|
||||
namespace NAPS2.ImportExport;
|
||||
|
||||
public interface IScannedImagePrinter
|
||||
@ -8,5 +10,5 @@ public interface IScannedImagePrinter
|
||||
/// <param name="images">The full list of images to print.</param>
|
||||
/// <param name="selectedImages">The list of selected images. If non-empty, the user will be presented an option to print selected.</param>
|
||||
/// <returns>True if the print completed, false if there was nothing to print or the user cancelled.</returns>
|
||||
Task<bool> PromptToPrint(IList<ProcessedImage> images, IList<ProcessedImage> selectedImages);
|
||||
Task<bool> PromptToPrint(Window parentWindow, IList<ProcessedImage> images, IList<ProcessedImage> selectedImages);
|
||||
}
|
@ -20,7 +20,7 @@ public class LinuxSystemCompat : ISystemCompat
|
||||
|
||||
public bool CanEmail => true;
|
||||
|
||||
public bool CanPrint => false;
|
||||
public bool CanPrint => true;
|
||||
|
||||
public bool ShouldRememberBackgroundOperations => false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user