Files
client/Services/Printing/ImagePrintJobExecutor.cs
2026-05-23 18:16:50 +08:00

88 lines
2.9 KiB
C#

using CloudPrint.Client.Models;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
namespace CloudPrint.Client.Services.Printing;
public sealed class ImagePrintJobExecutor : IPrintJobExecutor
{
private readonly IWindowsPrintQueueService _queueService;
private static readonly HashSet<string> SupportedExtensions = new(StringComparer.OrdinalIgnoreCase)
{
".jpg", ".jpeg", ".png", ".bmp", ".gif"
};
public ImagePrintJobExecutor(IWindowsPrintQueueService queueService)
{
_queueService = queueService;
}
public bool CanHandle(PrintJob job)
{
return SupportedExtensions.Contains(Path.GetExtension(job.FilePath));
}
public Task ExecuteAsync(PrintJob job, IProgress<int>? progress, CancellationToken cancellationToken = default)
{
PrintFileGuards.EnsurePrintableFile(job);
return Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
using var image = Image.FromFile(job.FilePath);
using var document = new PrintDocument
{
DocumentName = string.IsNullOrWhiteSpace(job.FileName) ? job.JobNo : job.FileName,
PrinterSettings =
{
PrinterName = job.PrinterName,
Copies = (short)Math.Clamp(job.Copies, 1, short.MaxValue)
}
};
if (document.PrinterSettings.CanDuplex)
{
document.PrinterSettings.Duplex = job.Duplex ? Duplex.Vertical : Duplex.Simplex;
}
document.DefaultPageSettings.Color = job.Color;
document.PrintPage += (_, args) => DrawImageToPage(image, args);
progress?.Report(20);
document.Print();
CaptureWindowsJob(job, document.DocumentName);
progress?.Report(100);
}, cancellationToken);
}
private void CaptureWindowsJob(PrintJob job, string documentName)
{
var queueJob = _queueService.FindLatestJob(job.PrinterName, documentName);
if (queueJob is null)
{
return;
}
job.WindowsJobId = queueJob.JobId;
job.WindowsJobStatus = queueJob.Status;
}
private static void DrawImageToPage(Image image, PrintPageEventArgs args)
{
if (args.Graphics is null)
{
throw new InvalidOperationException("打印图形上下文不可用");
}
var bounds = args.MarginBounds;
var ratio = Math.Min(bounds.Width / (double)image.Width, bounds.Height / (double)image.Height);
var width = (int)(image.Width * ratio);
var height = (int)(image.Height * ratio);
var x = bounds.Left + (bounds.Width - width) / 2;
var y = bounds.Top + (bounds.Height - height) / 2;
args.Graphics.DrawImage(image, x, y, width, height);
args.HasMorePages = false;
}
}