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 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? 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; } }