177 lines
6.4 KiB
C#
177 lines
6.4 KiB
C#
using Microsoft.Extensions.Options;
|
|
using PrintService.Models;
|
|
using System.Drawing;
|
|
using System.Drawing.Printing;
|
|
|
|
namespace PrintService.Services;
|
|
|
|
/// <summary>
|
|
/// Handles printing to Windows print queue with tray control
|
|
/// </summary>
|
|
public class PrinterService
|
|
{
|
|
private readonly AppSettings _settings;
|
|
private readonly ILogger<PrinterService> _logger;
|
|
|
|
public PrinterService(IOptions<AppSettings> settings, ILogger<PrinterService> logger)
|
|
{
|
|
_settings = settings.Value;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Print document to specified printer with tray sequence
|
|
/// </summary>
|
|
public void Print(string content, DocumentConfig config, string originalFileName)
|
|
{
|
|
if (config.TraySequence.Length == 0)
|
|
{
|
|
throw new InvalidOperationException("No tray sequence defined for document type");
|
|
}
|
|
|
|
var lines = content.Split(new[] { '\r', '\n' }, StringSplitOptions.None);
|
|
var linesPerPage = CalculateLinesPerPage(config);
|
|
var currentPageIndex = 0;
|
|
|
|
var printDoc = new PrintDocument
|
|
{
|
|
PrinterSettings = { PrinterName = config.PrinterName }
|
|
};
|
|
|
|
// Handle PDF output if using Microsoft Print to PDF
|
|
if (config.PrinterName.Equals("Microsoft Print to PDF", StringComparison.OrdinalIgnoreCase) &&
|
|
!string.IsNullOrEmpty(config.OutputPath))
|
|
{
|
|
Directory.CreateDirectory(config.OutputPath);
|
|
var pdfFileName = Path.GetFileNameWithoutExtension(originalFileName) + ".pdf";
|
|
var pdfPath = Path.Combine(config.OutputPath, pdfFileName);
|
|
|
|
printDoc.PrinterSettings.PrintToFile = true;
|
|
printDoc.PrinterSettings.PrintFileName = pdfPath;
|
|
|
|
_logger.LogInformation("PDF will be saved to: {Path}", pdfPath);
|
|
}
|
|
|
|
// Verify printer exists
|
|
if (!PrinterSettings.InstalledPrinters.Cast<string>().Contains(config.PrinterName))
|
|
{
|
|
throw new InvalidOperationException($"Printer '{config.PrinterName}' not found");
|
|
}
|
|
|
|
printDoc.PrintPage += (sender, e) =>
|
|
{
|
|
if (e.Graphics == null || e.PageSettings == null)
|
|
return;
|
|
|
|
// Select tray for current page
|
|
var trayIndex = config.TraySequence[currentPageIndex % config.TraySequence.Length];
|
|
|
|
try
|
|
{
|
|
// Map logical tray number to PaperSource
|
|
var paperSource = GetPaperSource(printDoc.PrinterSettings, trayIndex);
|
|
if (paperSource != null)
|
|
{
|
|
e.PageSettings.PaperSource = paperSource;
|
|
if (_settings.VerboseLogging)
|
|
{
|
|
_logger.LogDebug("Page {Page}: Using tray {Tray} ({Source})",
|
|
currentPageIndex + 1, trayIndex, paperSource.SourceName);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to set tray {Tray}, using default", trayIndex);
|
|
}
|
|
|
|
// Render page content
|
|
RenderPage(e.Graphics, lines, currentPageIndex * linesPerPage, linesPerPage, config);
|
|
|
|
currentPageIndex++;
|
|
e.HasMorePages = (currentPageIndex < config.TraySequence.Length);
|
|
};
|
|
|
|
_logger.LogInformation("Printing to {Printer} with {Pages} pages",
|
|
config.PrinterName, config.TraySequence.Length);
|
|
|
|
printDoc.Print();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Render page content using Graphics API
|
|
/// </summary>
|
|
private void RenderPage(Graphics graphics, string[] lines, int startLine, int linesPerPage, DocumentConfig config)
|
|
{
|
|
var font = new Font(config.FontName, config.FontSize);
|
|
var brush = Brushes.Black;
|
|
var lineHeight = font.GetHeight(graphics);
|
|
|
|
var x = (float)config.HorizontalOffset;
|
|
var y = (float)config.VerticalOffset;
|
|
|
|
var endLine = Math.Min(startLine + linesPerPage, lines.Length);
|
|
|
|
for (int i = startLine; i < endLine; i++)
|
|
{
|
|
if (i < lines.Length)
|
|
{
|
|
graphics.DrawString(lines[i], font, brush, x, y);
|
|
y += lineHeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate lines per page based on font and page size
|
|
/// </summary>
|
|
private int CalculateLinesPerPage(DocumentConfig config)
|
|
{
|
|
// Estimate: standard letter size is 11 inches, at 10pt font ~66 lines
|
|
// This is simplified; in production you'd calculate based on actual page dimensions
|
|
var estimatedLineHeight = config.FontSize * 1.2f; // points
|
|
var pageHeightInPoints = 11 * 72; // 11 inches * 72 points per inch
|
|
return (int)Math.Floor(pageHeightInPoints / estimatedLineHeight);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get PaperSource by logical tray number
|
|
/// </summary>
|
|
private PaperSource? GetPaperSource(PrinterSettings printerSettings, int trayNumber)
|
|
{
|
|
// Try to find by RawKind (tray number)
|
|
foreach (PaperSource source in printerSettings.PaperSources)
|
|
{
|
|
// Some printers use RawKind directly as tray number
|
|
if (source.RawKind == trayNumber ||
|
|
source.RawKind == (trayNumber + 256)) // Some drivers offset by 256
|
|
{
|
|
return source;
|
|
}
|
|
}
|
|
|
|
// Fallback: use by index if available
|
|
if (trayNumber > 0 && trayNumber <= printerSettings.PaperSources.Count)
|
|
{
|
|
return printerSettings.PaperSources[trayNumber - 1];
|
|
}
|
|
|
|
_logger.LogWarning("Could not map tray {Tray} to PaperSource", trayNumber);
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// List available paper sources for a printer (for debugging/configuration)
|
|
/// </summary>
|
|
public void ListPaperSources(string printerName)
|
|
{
|
|
var printDoc = new PrintDocument { PrinterSettings = { PrinterName = printerName } };
|
|
|
|
_logger.LogInformation("Available paper sources for {Printer}:", printerName);
|
|
foreach (PaperSource source in printDoc.PrinterSettings.PaperSources)
|
|
{
|
|
_logger.LogInformation(" - {Name} (RawKind: {Kind})", source.SourceName, source.RawKind);
|
|
}
|
|
}
|
|
}
|