From 147265358fadecfe85351dff4f8c3711b9ca13bd Mon Sep 17 00:00:00 2001 From: EugeneTes Date: Wed, 14 Jan 2026 11:47:43 +0100 Subject: [PATCH] kitchen receipt + html printer --- EpsonTest/Program.cs | 335 +++++---- Inspectron.Epson/EpsonPrinter.cs | 2 +- Inspectron.Epson/HtmlPrinter.cs | 700 ++++++++++++++++++ Inspectron.Epson/IEpsonPrinter.cs | 181 +++++ .../Printers/TM-T30IIITranslated.cs | 7 +- .../Printers/TM-U220IITranslated.cs | 2 +- .../Printers/Utils/FinalReceipt/Models.cs | 18 +- .../Utils/FinalReceipt/ReceiptConverter.cs | 52 +- .../KitchenReceipt/KitchenReceiptConverter.cs | 109 +++ .../Printers/Utils/KitchenReceipt/Models.cs | 92 +++ .../Printers/Utils/KitchenReceiptPrinter.cs | 2 +- .../Printers/Utils/PrintCommand.cs | 16 + .../Printers/Utils/ReceiptTranslator.cs | 6 +- .../WorkAreaSources/JamesWorkAreaSource.cs | 2 +- Screenshot 2025-12-14 201821_0bd9ce17.png | Bin 10057 -> 0 bytes kitchen_receipt.jpg | Bin 0 -> 64211 bytes 16 files changed, 1346 insertions(+), 178 deletions(-) create mode 100644 Inspectron.Epson/HtmlPrinter.cs create mode 100644 Inspectron.Epson/IEpsonPrinter.cs create mode 100644 Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverter.cs create mode 100644 Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs create mode 100644 Inspectron.Epson/PrintServer/Printers/Utils/PrintCommand.cs delete mode 100644 Screenshot 2025-12-14 201821_0bd9ce17.png create mode 100644 kitchen_receipt.jpg diff --git a/EpsonTest/Program.cs b/EpsonTest/Program.cs index 83585f5..04d2c17 100644 --- a/EpsonTest/Program.cs +++ b/EpsonTest/Program.cs @@ -1,12 +1,14 @@ using Inspectron.Epson; using Inspectron.Epson.PrintServer.Printers.Utils; using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe; +using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt; using Inspectron.Epson.SOAP; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using System.Text; using System.Text.Json; using System.Xml.Linq; +using FinalReceipt = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.FinalReceipt; //SoapEpsonPrinter printer = new SoapEpsonPrinter("localhost:8888"); @@ -56,125 +58,202 @@ using System.Xml.Linq; //Console.ReadLine(); -//var receipt = new Receipt +var receipt = new FinalReceipt +{ + CompanyName = "Klingler Gastro AG", + Address1 = "Münzplatz 3", + Address2 = "CH-8001 Zürich", + Phone = "043 321 22 22", + ReceiptNumber = "1-81-202", + DateTime = new DateTime(2025, 12, 16, 14, 58, 0), + Guests = 2, + Total = 160.00m, + Currency = "CHF", + TotalInAlternateCurrency = 172.80m, + AlternateCurrency = "EUR", + PaymentMethod = "MASTER", + PaymentAmount = 160.00m, + WaiterName = "Yves", + Terminal = "Hauptkasse ZH", + TableNumber = "12", + VatNumber = "CHE-449.635.880 MWST", + ThankYouMessage = "Das Team bedankt sich herzlich für Ihren", + GoodbyeMessageLine1 = "Besuch.", + GoodbyeMessageLine2 = "Auf Wiedersehen." +}; + +// Add items +receipt.Items.Add(new ReceiptItem +{ + Quantity = 1, + Description = "San Pellegrino 50cl", + UnitPrice = 6.50m, + TotalPrice = 6.50m, + TaxCategory = "A" +}); + +receipt.Items.Add(new ReceiptItem +{ + Quantity = 1, + Description = "Panna 50cl", + UnitPrice = 6.50m, + TotalPrice = 6.50m, + TaxCategory = "A" +}); + +receipt.Items.Add(new ReceiptItem +{ + Quantity = 1, + Description = "Granini Tomatensaft", + UnitPrice = 5.50m, + TotalPrice = 5.50m, + TaxCategory = "A" +}); + +receipt.Items.Add(new ReceiptItem +{ + Quantity = 2, + Description = "Business Lunch Menu Seco", + UnitPrice = 44.00m, + TotalPrice = 88.00m, + TaxCategory = "A" +}); + +receipt.Items.Add(new ReceiptItem +{ + Quantity = 2, + Description = "Brunello di Montalcino 1", + UnitPrice = 16.00m, + TotalPrice = 32.00m, + TaxCategory = "A" +}); + +receipt.Items.Add(new ReceiptItem +{ + Quantity = 2, + Description = "Espresso", + UnitPrice = 5.50m, + TotalPrice = 11.00m, + TaxCategory = "A" +}); + +receipt.Items.Add(new ReceiptItem +{ + Quantity = 1, + Description = "Tip", + UnitPrice = 10.50m, + TotalPrice = 10.50m, + TaxCategory = "B" +}); + +// Add tax breakdown +receipt.TaxBreakdown.Add(new TaxInfo +{ + Category = "A", + Rate = 8.1m, + Gross = 149.50m, + Net = 138.30m, + TaxAmount = 11.20m, + Currency = "CHF" +}); + +receipt.TaxBreakdown.Add(new TaxInfo +{ + Category = "B", + Rate = 0m, + Gross = 10.50m, + Net = 10.50m, + TaxAmount = 0.00m, + Currency = "CHF" +}); + + +// Convert to print commands +var converter = new ReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); +var printCommands = converter.ConvertToPrintCommands(receipt); + + + + +// Print the commands +Console.WriteLine("=== PRINT COMMANDS ===\n"); +var printer = new HtmlPrinter(@".\test.html", paperWidth: 384); +await printer.ConnectAsync(""); +await printer.SetAbsolutePrintPosition(97); +await printer.LoadImageAsync("ristorante-klinglers.ch-logo_white_bg.png", 390); +await printer.SetAbsolutePrintPosition(0); +await printer.PrintLoadedImage(); +await Task.Delay(200); +await printer.FeedLinesAsync(1); +await printer.SetCustomLineSpacing(22); +foreach (var command in printCommands) +{ + string attributes = ""; + if (command.IsBig) attributes += "[BIG] "; + if (command.IsBold) attributes += "[BOLD] "; + + Console.WriteLine($"{attributes}{command.Text}"); + + if (command.IsBig) + { + await printer.SetFontSizeAsync(2, 1); + } + else + { + await printer.SetFontSizeAsync(1, 1); + } + //await Task.Delay(200); + + await printer.SetEmphasized(command.IsBold); + //await Task.Delay(200); + + await printer.PrintTextAsync(command.Text + "\n"); + //await Task.Delay(200); + +} + + +//var receipt = new KitchenReceipt //{ -// CompanyName = "Klingler Gastro AG", -// Address1 = "Münzplatz 3", -// Address2 = "CH-8001 Zürich", -// Phone = "043 321 22 22", -// ReceiptNumber = "1-81-202", -// DateTime = new DateTime(2025, 12, 16, 14, 58, 0), -// Guests = 2, -// Total = 160.00m, -// Currency = "CHF", -// TotalInAlternateCurrency = 172.80m, -// AlternateCurrency = "EUR", -// PaymentMethod = "MASTER", -// PaymentAmount = 160.00m, -// ServerName = "Yves", -// Terminal = "Hauptkasse ZH", -// TableNumber = "12", -// VatNumber = "CHE-449.635.880 MWST", -// ThankYouMessage = "Das Team bedankt sich herzlich für Ihren", -// GoodbyeMessageLine1 = "Besuch.", -// GoodbyeMessageLine2 = "Auf Wiedersehen." +// Title = "Warme Küche", +// TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0), +// ReceiptNumber = "132018166", +// WaiterName = "Mariano Amato", +// WaiterId = "32 (VK Restaurant)", +// TableNumber = 22 //}; -//// Add items -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 1, -// Description = "San Pellegrino 50cl", -// UnitPrice = 6.50m, -// TotalPrice = 6.50m, -// TaxCategory = "A" -//}); +//// Add dishes (this section can be empty if no dishes were ordered) -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 1, -// Description = "Panna 50cl", -// UnitPrice = 6.50m, -// TotalPrice = 6.50m, -// TaxCategory = "A" -//}); +//receipt.Gangs.Add(new Gang(1, "Gang")); +//receipt.Gangs.Add(new Gang(2, "Gang")); -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 1, -// Description = "Granini Tomatensaft", -// UnitPrice = 5.50m, -// TotalPrice = 5.50m, -// TaxCategory = "A" -//}); - -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 2, -// Description = "Business Lunch Menu Seco", -// UnitPrice = 44.00m, -// TotalPrice = 88.00m, -// TaxCategory = "A" -//}); - -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 2, -// Description = "Brunello di Montalcino 1", -// UnitPrice = 16.00m, -// TotalPrice = 32.00m, -// TaxCategory = "A" -//}); - -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 2, -// Description = "Espresso", -// UnitPrice = 5.50m, -// TotalPrice = 11.00m, -// TaxCategory = "A" -//}); - -//receipt.Items.Add(new ReceiptItem -//{ -// Quantity = 1, -// Description = "Tip", -// UnitPrice = 10.50m, -// TotalPrice = 10.50m, -// TaxCategory = "B" -//}); - -//// Add tax breakdown -//receipt.TaxBreakdown.Add(new TaxInfo -//{ -// Category = "A", -// Rate = 8.1m, -// Gross = 149.50m, -// Net = 138.30m, -// TaxAmount = 11.20m, -// Currency = "CHF" -//}); - -//receipt.TaxBreakdown.Add(new TaxInfo -//{ -// Category = "B", -// Rate = 0m, -// Gross = 10.50m, -// Net = 10.50m, -// TaxAmount = 0.00m, -// Currency = "CHF" -//}); +//receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi")); +//receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); +//receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")); +//receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")); -//// Convert to print commands -//var converter = new ReceiptConverter(lineWidth: 48, bigFontLineWidth: 24); +//receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi")); +//receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); +//receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki")); +//receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco")); + +//receipt.Dishes.Add(new Dish(1, "Avocado Sashimi")); +//receipt.Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl")); +//receipt.Dishes.Add(new Dish(1, "Beef Tataki")); +//receipt.Dishes.Add(new Dish(1, "Salmon Taco")); + + +//// Add additional info +//receipt.AdditionalInfo.Add("1 x Amuse Bouche"); + +//KitchenReceiptConverter converter = new KitchenReceiptConverter(bigLineWidth: 20, lineWidth:33); //var printCommands = converter.ConvertToPrintCommands(receipt); -//// Print the commands //Console.WriteLine("=== PRINT COMMANDS ===\n"); -//await printer.SetAbsolutePrintPosition(97); -//await printer.LoadImageAsync("ristorante-klinglers.ch-logo_white_bg.png",390); -//await printer.SetAbsolutePrintPosition(0); +//var printer = new HtmlPrinter(@".\test.html", paperWidth: 258); +//await printer.ConnectAsync(""); //await Task.Delay(200); //await printer.FeedLinesAsync(1); //await printer.SetCustomLineSpacing(22); @@ -183,6 +262,7 @@ using System.Xml.Linq; // string attributes = ""; // if (command.IsBig) attributes += "[BIG] "; // if (command.IsBold) attributes += "[BOLD] "; +// if (command.IsRed) attributes += "[RED] "; // Console.WriteLine($"{attributes}{command.Text}"); @@ -194,6 +274,9 @@ using System.Xml.Linq; // { // await printer.SetFontSizeAsync(1, 1); // } + +// await printer.SetRedColor(command.IsRed); + // //await Task.Delay(200); // await printer.SetEmphasized(command.IsBold); @@ -230,24 +313,24 @@ using System.Xml.Linq; //await Task.Delay(200); //KitchenReceiptPrinter krp = new KitchenReceiptPrinter(33); -var receipt = new KitchenReceipt( - Location: "Warme Küche", - Date: "23-Okt-25 12:18 Nr.:13201B166", - Owner: "Mariano Amato\n32 (VK Restaurant)", - Tisch: "22", - items: new List - { - new KitchenGang("1. Gang"), - new KitchenProduct(1, "Avocado Sashimi"), - new KitchenProduct(1, "Baby Spinach Salad with Truffl"), - new KitchenGang("2. Gang"), - new KitchenProduct(1, "Beef Tataki"), - new KitchenProduct(1, "Salmon Taco") - } -); +//var receipt = new TranslatedKitchenReceipt( +// Location: "Warme Küche", +// Date: "23-Okt-25 12:18 Nr.:13201B166", +// Owner: "Mariano Amato\n32 (VK Restaurant)", +// Tisch: "22", +// items: new List +// { +// new KitchenGang("1. Gang"), +// new KitchenProduct(1, "Avocado Sashimi"), +// new KitchenProduct(1, "Baby Spinach Salad with Truffl"), +// new KitchenGang("2. Gang"), +// new KitchenProduct(1, "Beef Tataki"), +// new KitchenProduct(1, "Salmon Taco") +// } +//); -var test = JsonSerializer.Serialize(receipt, new JsonSerializerOptions() { WriteIndented = true }); -Console.WriteLine(test); +//var test = JsonSerializer.Serialize(receipt, new JsonSerializerOptions() { WriteIndented = true }); +//Console.WriteLine(test); ////// Create printer with 42 character line width (default) //var commands = krp.ConvertToCommands(receipt); diff --git a/Inspectron.Epson/EpsonPrinter.cs b/Inspectron.Epson/EpsonPrinter.cs index 045bd8b..140a948 100644 --- a/Inspectron.Epson/EpsonPrinter.cs +++ b/Inspectron.Epson/EpsonPrinter.cs @@ -10,7 +10,7 @@ namespace Inspectron.Epson; /// /// Main SDK class for Epson TM-m30III printer operations /// -public class EpsonPrinter : IAsyncDisposable +public class EpsonPrinter : IEpsonPrinter { private readonly ILogger? _logger; private TcpClient? _tcpClient; diff --git a/Inspectron.Epson/HtmlPrinter.cs b/Inspectron.Epson/HtmlPrinter.cs new file mode 100644 index 0000000..1aa7413 --- /dev/null +++ b/Inspectron.Epson/HtmlPrinter.cs @@ -0,0 +1,700 @@ +using Microsoft.Extensions.Logging; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System.Text; + +namespace Inspectron.Epson; + +/// +/// HTML-based printer implementation that outputs to an HTML file, +/// simulating Epson thermal printer output for testing and preview purposes. +/// +public class HtmlPrinter : IEpsonPrinter +{ + private readonly ILogger? _logger; + private readonly string _outputPath; + private readonly int _paperWidth; + private readonly string _imageDirectory; + + private bool _isConnected; + private readonly StringBuilder _content = new(); + private int _imageCounter; + + // Current styling state + private EpsonCommands.PrinterFont _currentFont = EpsonCommands.PrinterFont.A; + private int _fontWidthMultiplier = 1; + private int _fontHeightMultiplier = 1; + private bool _isEmphasized; + private bool _isRedColor; + private bool _isQuadrupleMode; + private bool _isBiggerFontTM220; + private int _lineSpacing = 14; // Default line spacing in pixels (scaled for screen) + private int _absolutePosition; // Current X position offset + + // Loaded image buffer + private Image? _loadedImage; + private int _loadedImageMaxWidth; + + /// + /// Font size mappings for different Epson fonts (scaled for screen display) + /// Original dots: Font A: 12x24, Font B: 9x17, Font C: 9x24, Font D: 10x24, Font E: 12x24 + /// Scaled to ~0.5x for reasonable screen display + /// + private static readonly Dictionary FontSizes = new() + { + { EpsonCommands.PrinterFont.A, (6, 12) }, + { EpsonCommands.PrinterFont.B, (5, 9) }, + { EpsonCommands.PrinterFont.C, (5, 12) }, + { EpsonCommands.PrinterFont.D, (5, 12) }, + { EpsonCommands.PrinterFont.E, (6, 12) } + }; + + /// + public bool IsConnected => _isConnected; + + /// + /// Initialize a new instance of HtmlPrinter + /// + /// Path to the output HTML file + /// Paper width in pixels (default 384 for 80mm thermal printer) + /// Optional logger for diagnostic output + public HtmlPrinter(string outputPath, int paperWidth = 384, ILogger? logger = null) + { + _outputPath = outputPath; + _paperWidth = paperWidth; + _logger = logger; + + // Create image directory next to HTML file + var directory = Path.GetDirectoryName(outputPath) ?? "."; + var fileName = Path.GetFileNameWithoutExtension(outputPath); + _imageDirectory = Path.Combine(directory, $"{fileName}_images"); + } + + /// + public Task ConnectAsync(string ip, int port = 9100, int timeoutSeconds = 10) + { + _logger?.LogInformation("HtmlPrinter: Connecting (output: {Path}, paper width: {Width}px)", _outputPath, _paperWidth); + + // Create image directory if it doesn't exist + if (!Directory.Exists(_imageDirectory)) + { + Directory.CreateDirectory(_imageDirectory); + } + + // Clear previous content + _content.Clear(); + _imageCounter = 0; + ResetStylingState(); + + _isConnected = true; + WriteHtmlFile(); + + _logger?.LogInformation("HtmlPrinter: Connected successfully"); + return Task.CompletedTask; + } + + /// + public void Disconnect() + { + _logger?.LogDebug("HtmlPrinter: Disconnecting"); + + if (_isConnected) + { + WriteHtmlFile(); + } + + _loadedImage?.Dispose(); + _loadedImage = null; + _isConnected = false; + } + + /// + public Task GetPrinterStatusAsync() + { + _logger?.LogDebug("HtmlPrinter: Returning mock printer status (always ready)"); + return Task.FromResult(new PrinterStatus + { + RawByte = 0x12, // Online, cover closed + DrawerOpen = false, + IsOnline = true, + IsCoverClosed = true, + PaperFeedButtonPressed = false + }); + } + + /// + public Task GetOfflineStatusAsync() + { + _logger?.LogDebug("HtmlPrinter: Returning mock offline status (no issues)"); + return Task.FromResult(new OfflineStatus + { + RawByte = 0x12, + CoverOpen = false, + PaperFeedButton = false, + PaperEnd = false, + ErrorOccurred = false + }); + } + + /// + public Task GetErrorStatusAsync() + { + _logger?.LogDebug("HtmlPrinter: Returning mock error status (no errors)"); + return Task.FromResult(new ErrorStatus + { + RawByte = 0x12, + RecoverableError = false, + AutoCutterError = false, + UnrecoverableError = false, + AutoRecoveryError = false + }); + } + + /// + public Task GetPaperSensorStatusAsync() + { + _logger?.LogDebug("HtmlPrinter: Returning mock paper sensor status (paper present)"); + return Task.FromResult(new PaperSensorStatus + { + RawByte = 0x12, + PaperNearEnd = false, + PaperPresent = true + }); + } + + /// + public Task GetTM220StatusAsync() + { + _logger?.LogDebug("HtmlPrinter: Returning mock TM220 status"); + return Task.FromResult((byte)0x12); + } + + /// + public Task GetPrinterIdAsync() + { + _logger?.LogDebug("HtmlPrinter: Returning mock printer ID (0x01 = TM-T30III)"); + return Task.FromResult(0x01); + } + + /// + public Task GetOverallStatusAsync() + { + _logger?.LogInformation("HtmlPrinter: Returning mock overall status (ready)"); + return Task.FromResult(new OverallStatus + { + PrinterModel = "HtmlPrinter", + PrinterStatus = new PrinterStatus { RawByte = 0x12, IsOnline = true, IsCoverClosed = true }, + OfflineStatus = new OfflineStatus { RawByte = 0x12 }, + ErrorStatus = new ErrorStatus { RawByte = 0x12 }, + PaperStatus = new PaperSensorStatus { RawByte = 0x12, PaperPresent = true }, + StatusText = "READY - HTML Printer Simulator", + StatusIcon = "🟢", + IsReady = true, + Recommendations = new List() + }); + } + + /// + public Task InitAsync() + { + _logger?.LogInformation("HtmlPrinter: Initializing (resetting styling state)"); + ResetStylingState(); + return Task.CompletedTask; + } + + /// + public Task SetQuadrupleMode(bool enable) + { + _logger?.LogInformation("HtmlPrinter: {Action} quadruple mode", enable ? "Enabling" : "Disabling"); + _isQuadrupleMode = enable; + return Task.CompletedTask; + } + + /// + public Task SetRedColor(bool enable) + { + _logger?.LogInformation("HtmlPrinter: {Action} red color mode", enable ? "Enabling" : "Disabling"); + _isRedColor = enable; + return Task.CompletedTask; + } + + /// + public Task SetEmphasized(bool enable) + { + _logger?.LogInformation("HtmlPrinter: {Action} emphasized mode", enable ? "Enabling" : "Disabling"); + _isEmphasized = enable; + return Task.CompletedTask; + } + + /// + public Task SelectFont(EpsonCommands.PrinterFont font) + { + _logger?.LogInformation("HtmlPrinter: Selecting font {Font}", font); + _currentFont = font; + return Task.CompletedTask; + } + + /// + public Task SetBiggerFontTM220(bool enabled) + { + _logger?.LogInformation("HtmlPrinter: {Action} bigger font mode for TM-T20/220", enabled ? "Enabling" : "Disabling"); + _isBiggerFontTM220 = enabled; + return Task.CompletedTask; + } + + /// + public Task PrintTextAsync(string text) + { + EnsureConnected(); + _logger?.LogInformation("HtmlPrinter: Printing text ({Length} characters)", text.Length); + + var style = BuildCurrentStyle(); + var escapedText = EscapeHtml(text); + + // Handle newlines + escapedText = escapedText.TrimEnd('\n').Replace("\n", "
"); + + // Add margin-left for absolute positioning + var positionStyle = _absolutePosition > 0 ? $"margin-left: {_absolutePosition}px;" : ""; + + _content.AppendLine($"{escapedText}"); + + // Reset absolute position after printing + _absolutePosition = 0; + + WriteHtmlFile(); + return Task.CompletedTask; + } + + /// + public Task SetFontSizeAsync(int width, int height) + { + if (width < 1 || width > 8 || height < 1 || height > 8) + throw new ArgumentException("Size must be between 1 and 8"); + + _logger?.LogInformation("HtmlPrinter: Setting font size to {Width}x{Height}", width, height); + _fontWidthMultiplier = width; + _fontHeightMultiplier = height; + return Task.CompletedTask; + } + + /// + public async Task PrintTextAndCutAsync(string text, int feedLines = 5) + { + _logger?.LogInformation("HtmlPrinter: Printing text with cut ({Length} characters, {FeedLines} feed lines)", + text.Length, feedLines); + + await InitAsync(); + await PrintTextAsync(text); + await PrintTextAsync("\n"); + await FeedLinesAsync(feedLines); + await CutAsync(); + } + + /// + public Task PrintBuffer() + { + _logger?.LogDebug("HtmlPrinter: PrintBuffer (no-op for HTML)"); + return Task.CompletedTask; + } + + /// + public Task FeedLinesAsync(int lines) + { + EnsureConnected(); + _logger?.LogInformation("HtmlPrinter: Feeding {Lines} lines", lines); + + for (int i = 0; i < lines; i++) + { + _content.AppendLine($"
"); + } + + WriteHtmlFile(); + return Task.CompletedTask; + } + + /// + public Task CutAsync() + { + EnsureConnected(); + _logger?.LogInformation("HtmlPrinter: Cutting paper"); + + _content.AppendLine("
"); + + WriteHtmlFile(); + return Task.CompletedTask; + } + + /// + public async Task LoadImageAsync(string imagePath, int maxWidth = 384) + { + _logger?.LogInformation("HtmlPrinter: Loading image from file: {Path}", imagePath); + + if (!File.Exists(imagePath)) + { + throw new FileNotFoundException($"Image file not found: {imagePath}", imagePath); + } + + _loadedImage?.Dispose(); + _loadedImage = await Image.LoadAsync(imagePath); + _loadedImageMaxWidth = maxWidth; + } + + /// + public async Task LoadImageAsync(Stream imageStream, int maxWidth = 384) + { + _logger?.LogInformation("HtmlPrinter: Loading image from stream"); + + _loadedImage?.Dispose(); + _loadedImage = await Image.LoadAsync(imageStream); + _loadedImageMaxWidth = maxWidth; + } + + /// + public Task LoadImageAsync(Image image, int maxWidth = 384) + { + _logger?.LogInformation("HtmlPrinter: Loading image from ImageSharp object"); + + _loadedImage?.Dispose(); + _loadedImage = image.Clone(); + _loadedImageMaxWidth = maxWidth; + return Task.CompletedTask; + } + + /// + public async Task PrintLoadedImage() + { + EnsureConnected(); + + if (_loadedImage == null) + { + _logger?.LogWarning("HtmlPrinter: No image loaded to print"); + return; + } + + _logger?.LogInformation("HtmlPrinter: Printing loaded image"); + await RenderImageToHtml(_loadedImage, _loadedImageMaxWidth); + + _loadedImage.Dispose(); + _loadedImage = null; + } + + /// + public async Task PrintImageBitModeAsync(string imagePath, EpsonCommands.BitImageMode mode = EpsonCommands.BitImageMode.SingleDensity8Dot, int maxWidth = 10) + { + _logger?.LogInformation("HtmlPrinter: Printing image (bit mode) from file: {Path}", imagePath); + + if (!File.Exists(imagePath)) + { + throw new FileNotFoundException($"Image file not found: {imagePath}", imagePath); + } + + using var image = await Image.LoadAsync(imagePath); + await PrintImageBitModeAsync(image, mode, maxWidth); + } + + /// + public async Task PrintImageBitModeAsync(Stream imageStream, EpsonCommands.BitImageMode mode = EpsonCommands.BitImageMode.DoubleDensity24Dot, int maxWidth = 384) + { + _logger?.LogInformation("HtmlPrinter: Printing image (bit mode) from stream"); + + using var image = await Image.LoadAsync(imageStream); + await PrintImageBitModeAsync(image, mode, maxWidth); + } + + /// + public Task PrintImageBitModeAsync(Image image, EpsonCommands.BitImageMode mode, int maxWidth) + { + EnsureConnected(); + _logger?.LogInformation("HtmlPrinter: Printing image (bit mode) {Width}x{Height}", image.Width, image.Height); + + return RenderImageToHtml(image, maxWidth); + } + + /// + public Task SendRawCommandAsync(byte[] command) + { + _logger?.LogDebug("HtmlPrinter: SendRawCommandAsync ignored ({Length} bytes)", command.Length); + // Raw commands are ignored in HTML output + return Task.CompletedTask; + } + + /// + public Task SetAbsolutePrintPosition(int x) + { + if (x < 0 || x > 65535) + throw new ArgumentOutOfRangeException(nameof(x), "Position must be between 0 and 65535"); + + _logger?.LogInformation("HtmlPrinter: Setting absolute print position to {X}", x); + _absolutePosition = x; + return Task.CompletedTask; + } + + /// + public Task SetDefaultLineSpacing() + { + _logger?.LogInformation("HtmlPrinter: Setting default line spacing"); + _lineSpacing = 14; // Default (scaled for screen) + return Task.CompletedTask; + } + + /// + public Task SetCustomLineSpacing(int spacing = 24) + { + if (spacing < 0 || spacing > 255) + throw new ArgumentOutOfRangeException(nameof(spacing), "Spacing must be between 0 and 255"); + + _logger?.LogInformation("HtmlPrinter: Setting custom line spacing to {Spacing}", spacing); + // Convert dot spacing to approximate pixel spacing (scaled ~0.5x for screen) + _lineSpacing = (int)(spacing * 0.6); + return Task.CompletedTask; + } + + /// + public ValueTask DisposeAsync() + { + Disconnect(); + return ValueTask.CompletedTask; + } + + #region Private Methods + + private void ResetStylingState() + { + _currentFont = EpsonCommands.PrinterFont.A; + _fontWidthMultiplier = 1; + _fontHeightMultiplier = 1; + _isEmphasized = false; + _isRedColor = false; + _isQuadrupleMode = false; + _isBiggerFontTM220 = false; + _lineSpacing = 14; + _absolutePosition = 0; + } + + private string BuildCurrentStyle() + { + var styles = new List(); + + // Base font size from selected font + var (baseWidth, baseHeight) = FontSizes[_currentFont]; + + // Apply multipliers + int effectiveWidthMultiplier = _fontWidthMultiplier; + int effectiveHeightMultiplier = _fontHeightMultiplier; + + if (_isQuadrupleMode) + { + effectiveWidthMultiplier *= 2; + effectiveHeightMultiplier *= 2; + } + + if (_isBiggerFontTM220) + { + effectiveHeightMultiplier *= 2; + } + + int fontSize = baseHeight * effectiveHeightMultiplier; + styles.Add($"font-size: {fontSize}px"); + + // Letter spacing for width scaling (approximate) + if (effectiveWidthMultiplier > 1) + { + int letterSpacing = (effectiveWidthMultiplier) * baseWidth / 2; + styles.Add($"letter-spacing: {letterSpacing}px"); + } + + // Font weight + if (_isEmphasized) + { + styles.Add("font-weight: bold"); + } + + // Color + if (_isRedColor) + { + styles.Add("color: #cc0000"); + } + + // Line height based on current line spacing + styles.Add($"line-height: {_lineSpacing}px"); + + return string.Join("; ", styles) + ";"; + } + + private async Task RenderImageToHtml(Image sourceImage, int maxWidth) + { + // Clone and process the image (apply dithering like real printer) + using var processedImage = sourceImage.Clone(); + + // Resize if needed + if (processedImage.Width > maxWidth) + { + EpsonImageConverter.ResizeImage(processedImage, maxWidth); + } + + // Convert to grayscale + using var grayscaleImage = EpsonImageConverter.ConvertToGrayscale(processedImage); + + // Apply Floyd-Steinberg dithering + EpsonImageConverter.ApplyFloydSteinbergDithering(grayscaleImage); + + // Convert back to RGBA for saving + using var ditheredImage = new Image(grayscaleImage.Width, grayscaleImage.Height); + grayscaleImage.ProcessPixelRows(ditheredImage, (sourceAccessor, targetAccessor) => + { + for (int y = 0; y < sourceAccessor.Height; y++) + { + var sourceRow = sourceAccessor.GetRowSpan(y); + var targetRow = targetAccessor.GetRowSpan(y); + + for (int x = 0; x < sourceAccessor.Width; x++) + { + byte value = sourceRow[x].PackedValue; + targetRow[x] = new Rgba32(value, value, value, 255); + } + } + }); + + // Save image to file + _imageCounter++; + var imageName = $"image_{_imageCounter:D4}.png"; + var imagePath = Path.Combine(_imageDirectory, imageName); + + await ditheredImage.SaveAsync(imagePath, new PngEncoder()); + + // Get relative path for HTML + var htmlDir = Path.GetDirectoryName(_outputPath) ?? "."; + var relativeImagePath = Path.GetRelativePath(htmlDir, imagePath).Replace('\\', '/'); + + // Add to HTML content + var positionStyle = _absolutePosition > 0 ? $"margin-left: {_absolutePosition}px;" : ""; + _content.AppendLine($"
\"Printed
"); + + // Reset absolute position + _absolutePosition = 0; + + WriteHtmlFile(); + + _logger?.LogInformation("HtmlPrinter: Image saved to {Path}", imagePath); + } + + private void WriteHtmlFile() + { + var html = GenerateHtml(); + File.WriteAllText(_outputPath, html, Encoding.UTF8); + _logger?.LogDebug("HtmlPrinter: HTML file written to {Path}", _outputPath); + } + + private string GenerateHtml() + { + return $@" + + + + + Epson Printer Output + + + +
+{_content} +
+ +"; + } + + private static string EscapeHtml(string text) + { + return text + .Replace("&", "&") + .Replace("<", "<") + .Replace(">", ">") + .Replace("\"", """) + .Replace("'", "'"); + } + + private void EnsureConnected() + { + if (!_isConnected) + { + throw new EpsonConnectionException("Not connected. Call ConnectAsync first."); + } + } + + #endregion +} diff --git a/Inspectron.Epson/IEpsonPrinter.cs b/Inspectron.Epson/IEpsonPrinter.cs new file mode 100644 index 0000000..d3008b1 --- /dev/null +++ b/Inspectron.Epson/IEpsonPrinter.cs @@ -0,0 +1,181 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; + +namespace Inspectron.Epson; + +/// +/// Interface for Epson printer operations, allowing swappable implementations +/// (e.g., real printer vs HTML output for testing/preview) +/// +public interface IEpsonPrinter : IAsyncDisposable +{ + /// + /// Returns true if connected to the printer + /// + bool IsConnected { get; } + + /// + /// Connect to the printer + /// + /// Printer IP address (or identifier for non-network implementations) + /// Printer port (default 9100) + /// Connection timeout in seconds (default 10) + Task ConnectAsync(string ip, int port = 9100, int timeoutSeconds = 10); + + /// + /// Disconnect from the printer + /// + void Disconnect(); + + /// + /// Get general printer status + /// + Task GetPrinterStatusAsync(); + + /// + /// Get offline status (reasons for offline) + /// + Task GetOfflineStatusAsync(); + + /// + /// Get error status + /// + Task GetErrorStatusAsync(); + + /// + /// Get paper sensor status + /// + Task GetPaperSensorStatusAsync(); + + /// + /// Get TM-T20/220 specific status byte + /// + Task GetTM220StatusAsync(); + + /// + /// Get printer model/ID + /// + Task GetPrinterIdAsync(); + + /// + /// Get comprehensive overall status with health assessment + /// + Task GetOverallStatusAsync(); + + /// + /// Initialize the printer + /// + Task InitAsync(); + + /// + /// Enable or disable quadruple size mode + /// + Task SetQuadrupleMode(bool enable); + + /// + /// Enable or disable red color printing + /// + Task SetRedColor(bool enable); + + /// + /// Enable or disable emphasized (bold) mode + /// + Task SetEmphasized(bool enable); + + /// + /// Select printer font + /// + Task SelectFont(EpsonCommands.PrinterFont font); + + /// + /// Enable or disable bigger font mode for TM-T20/220 + /// + Task SetBiggerFontTM220(bool enabled); + + /// + /// Print text to the printer + /// + Task PrintTextAsync(string text); + + /// + /// Set font size (magnification) + /// + /// Width magnification (1-8) + /// Height magnification (1-8) + Task SetFontSizeAsync(int width, int height); + + /// + /// Print text, feed paper, and cut + /// + Task PrintTextAndCutAsync(string text, int feedLines = 5); + + /// + /// Print the current buffer + /// + Task PrintBuffer(); + + /// + /// Feed specified number of lines + /// + Task FeedLinesAsync(int lines); + + /// + /// Cut the paper + /// + Task CutAsync(); + + /// + /// Load an image from a file path into the printer buffer + /// + Task LoadImageAsync(string imagePath, int maxWidth = 384); + + /// + /// Load an image from a stream into the printer buffer + /// + Task LoadImageAsync(Stream imageStream, int maxWidth = 384); + + /// + /// Load an image from an ImageSharp Image object into the printer buffer + /// + Task LoadImageAsync(Image image, int maxWidth = 384); + + /// + /// Print the previously loaded image + /// + Task PrintLoadedImage(); + + /// + /// Print an image using bit-image mode from a file path + /// + Task PrintImageBitModeAsync(string imagePath, EpsonCommands.BitImageMode mode = EpsonCommands.BitImageMode.SingleDensity8Dot, int maxWidth = 10); + + /// + /// Print an image using bit-image mode from a stream + /// + Task PrintImageBitModeAsync(Stream imageStream, EpsonCommands.BitImageMode mode = EpsonCommands.BitImageMode.DoubleDensity24Dot, int maxWidth = 384); + + /// + /// Print an image using bit-image mode from an ImageSharp Image object + /// + Task PrintImageBitModeAsync(Image image, EpsonCommands.BitImageMode mode, int maxWidth); + + /// + /// Send raw ESC/POS command bytes to the printer + /// + Task SendRawCommandAsync(byte[] command); + + /// + /// Set the absolute horizontal print position + /// + Task SetAbsolutePrintPosition(int x); + + /// + /// Set default line spacing + /// + Task SetDefaultLineSpacing(); + + /// + /// Set custom line spacing + /// + Task SetCustomLineSpacing(int spacing = 24); +} diff --git a/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs b/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs index 5e1a24d..772ad55 100644 --- a/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs +++ b/Inspectron.Epson/PrintServer/Printers/TM-T30IIITranslated.cs @@ -2,6 +2,7 @@ using Inspectron.Epson.PrintServer.Printers.Utils; using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe; using Inspectron.Epson.PrintServer.PrintServices; +using FinalReceipt = Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe.FinalReceipt; namespace Inspectron.Epson.PrintServer.Printers; @@ -35,10 +36,10 @@ public class TM_T30IIITranslated:IPrinter public async Task PrintTextAsync(string text) { - Receipt? receipt; + FinalReceipt? receipt; try { - receipt = JsonSerializer.Deserialize(text); + receipt = JsonSerializer.Deserialize(text); } catch { @@ -84,7 +85,7 @@ public class TM_T30IIITranslated:IPrinter ReceiptTranslator translator = new ReceiptTranslator(); var ast = translator.ParseReceipt(text); KitchenReceiptPrinter printer = new KitchenReceiptPrinter(lineWidth: 33, 21); - var commands = printer.ConvertToCommands((KitchenReceipt)ast); + var commands = printer.ConvertToCommands((TranslatedKitchenReceipt)ast); foreach (KitchenPrintCommand command in commands) { if (command.IsBig) diff --git a/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs b/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs index 261d0ac..0887143 100644 --- a/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs +++ b/Inspectron.Epson/PrintServer/Printers/TM-U220IITranslated.cs @@ -37,7 +37,7 @@ public class TM_U220IITranslated:IPrinter ReceiptTranslator translator = new ReceiptTranslator(); var ast = translator.ParseReceipt(text); KitchenReceiptPrinter printer = new KitchenReceiptPrinter(lineWidth:33,21); - var commands = printer.ConvertToCommands((KitchenReceipt)ast); + var commands = printer.ConvertToCommands((TranslatedKitchenReceipt)ast); foreach (KitchenPrintCommand command in commands) { await _printer.SetBiggerFontTM220(command.IsBig); diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs index 8dedbe0..4926a88 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/Models.cs @@ -1,6 +1,6 @@ namespace Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe; -public class Receipt +public class FinalReceipt { public string CompanyName { get; set; } public string Address1 { get; set; } @@ -17,7 +17,7 @@ public class Receipt public string PaymentMethod { get; set; } public decimal PaymentAmount { get; set; } public List TaxBreakdown { get; set; } = new List(); - public string ServerName { get; set; } + public string WaiterName { get; set; } public string Terminal { get; set; } public string TableNumber { get; set; } public string VatNumber { get; set; } @@ -43,18 +43,4 @@ public class TaxInfo public decimal Net { get; set; } public decimal TaxAmount { get; set; } public string Currency { get; set; } -} - -public class PrintCommand -{ - public string Text { get; set; } - public bool IsBig { get; set; } - public bool IsBold { get; set; } - - public PrintCommand(string text, bool isBig = false, bool isBold = false) - { - Text = text; - IsBig = isBig; - IsBold = isBold; - } } \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs index b0ee66d..ab917ec 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/FinalReceipt/ReceiptConverter.cs @@ -11,26 +11,26 @@ public class ReceiptConverter _bigFontLineWidth = bigFontLineWidth; } - public List ConvertToPrintCommands(Receipt receipt) + public List ConvertToPrintCommands(FinalReceipt finalReceipt) { var commands = new List(); // Header - Company info - commands.Add(new PrintCommand(Center(receipt.CompanyName, false))); - commands.Add(new PrintCommand(Center(receipt.Address1, false))); - commands.Add(new PrintCommand(Center(receipt.Address2, false))); - commands.Add(new PrintCommand(Center(receipt.Phone, false))); + commands.Add(new PrintCommand(Center(finalReceipt.CompanyName, false))); + commands.Add(new PrintCommand(Center(finalReceipt.Address1, false))); + commands.Add(new PrintCommand(Center(finalReceipt.Address2, false))); + commands.Add(new PrintCommand(Center(finalReceipt.Phone, false))); commands.Add(new PrintCommand("")); commands.Add(new PrintCommand("")); - // Receipt info - string receiptLine = $"Rechnung Nr. {receipt.ReceiptNumber}".PadRight(_lineWidth/2)+$"{receipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth/2); + // FinalReceipt info + string receiptLine = $"Rechnung Nr. {finalReceipt.ReceiptNumber}".PadRight(_lineWidth/2)+$"{finalReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth/2); commands.Add(new PrintCommand(receiptLine,isBold:true)); - commands.Add(new PrintCommand($"Guests: {receipt.Guests}")); + commands.Add(new PrintCommand($"Guests: {finalReceipt.Guests}")); commands.Add(new PrintCommand("")); // Items - foreach (var item in receipt.Items) + foreach (var item in finalReceipt.Items) { string quantityDesc = $"{item.Quantity}x {item.Description}"; string prices = $"{item.UnitPrice:F2}"+$"{item.TotalPrice:F2}".PadLeft(7)+$" {item.TaxCategory}"; @@ -48,31 +48,31 @@ public class ReceiptConverter commands.Add(new PrintCommand("")); //Reini // Total - string totalLine = $"Summe: {receipt.Total:F2} {receipt.Currency}"; + string totalLine = $"Summe: {finalReceipt.Total:F2} {finalReceipt.Currency}"; commands.Add(new PrintCommand(Center(totalLine, true), true, true)); commands.Add(new PrintCommand("")); // Alternate currency - if (receipt.TotalInAlternateCurrency.HasValue) + if (finalReceipt.TotalInAlternateCurrency.HasValue) { - string altCurrencyLine = $"{receipt.TotalInAlternateCurrency:F2} {receipt.AlternateCurrency}"; + string altCurrencyLine = $"{finalReceipt.TotalInAlternateCurrency:F2} {finalReceipt.AlternateCurrency}"; commands.Add(new PrintCommand(altCurrencyLine.PadLeft(_lineWidth))); commands.Add(new PrintCommand("")); } // Payment method - string paymentLine = $"{receipt.PaymentMethod}"; - string paymentAmount = $"{receipt.PaymentAmount:F2} {receipt.Currency}"; + string paymentLine = $"{finalReceipt.PaymentMethod}"; + string paymentAmount = $"{finalReceipt.PaymentAmount:F2} {finalReceipt.Currency}"; int paymentSpaces = _lineWidth - paymentLine.Length - paymentAmount.Length; if (paymentSpaces < 1) paymentSpaces = 1; commands.Add(new PrintCommand(paymentLine + new string(' ', paymentSpaces) + paymentAmount,isBold:true)); commands.Add(new PrintCommand("")); // Tax breakdown - foreach (var tax in receipt.TaxBreakdown) + foreach (var tax in finalReceipt.TaxBreakdown) { string taxLine = "MwSt %".PadRight(_lineWidth/4)+" Brutto".PadRight(_lineWidth / 4) + " Netto".PadRight(_lineWidth / 4) + "MwSt".PadLeft(_lineWidth / 4); - if (receipt.TaxBreakdown.IndexOf(tax) == 0) + if (finalReceipt.TaxBreakdown.IndexOf(tax) == 0) { commands.Add(new PrintCommand(taxLine)); } @@ -83,22 +83,22 @@ public class ReceiptConverter commands.Add(new PrintCommand("")); // Footer info - //commands.Add(new PrintCommand(Center($"Bedient von: {receipt.ServerName}", false))); - //commands.Add(new PrintCommand(Center($"Terminal: {receipt.Terminal}", false))); - //commands.Add(new PrintCommand(Center($"Tisch: {receipt.TableNumber}", false))); - commands.Add(new PrintCommand($"Bedient von:".PadLeft(_lineWidth / 2) + $" {receipt.ServerName}")); - commands.Add(new PrintCommand($"Terminal:".PadLeft(_lineWidth / 2) + $" {receipt.Terminal}")); - commands.Add(new PrintCommand($"Tisch:".PadLeft(_lineWidth / 2)+$" {receipt.TableNumber}")); + //commands.Add(new PrintCommand(Center($"Bedient von: {finalReceipt.WaiterName}", false))); + //commands.Add(new PrintCommand(Center($"Terminal: {finalReceipt.Terminal}", false))); + //commands.Add(new PrintCommand(Center($"Tisch: {finalReceipt.TableNumber}", false))); + commands.Add(new PrintCommand($"Bedient von:".PadLeft(_lineWidth / 2) + $" {finalReceipt.WaiterName}")); + commands.Add(new PrintCommand($"Terminal:".PadLeft(_lineWidth / 2) + $" {finalReceipt.Terminal}")); + commands.Add(new PrintCommand($"Tisch:".PadLeft(_lineWidth / 2)+$" {finalReceipt.TableNumber}")); commands.Add(new PrintCommand("")); commands.Add(new PrintCommand("")); // VAT number - commands.Add(new PrintCommand(Center(receipt.VatNumber, false))); + commands.Add(new PrintCommand(Center(finalReceipt.VatNumber, false))); // Thank you message - commands.Add(new PrintCommand(Center(receipt.ThankYouMessage, false))); - commands.Add(new PrintCommand(Center(receipt.GoodbyeMessageLine1, false))); - commands.Add(new PrintCommand(Center(receipt.GoodbyeMessageLine2, false))); + commands.Add(new PrintCommand(Center(finalReceipt.ThankYouMessage, false))); + commands.Add(new PrintCommand(Center(finalReceipt.GoodbyeMessageLine1, false))); + commands.Add(new PrintCommand(Center(finalReceipt.GoodbyeMessageLine2, false))); return commands; } diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverter.cs new file mode 100644 index 0000000..1ebb2f1 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/KitchenReceiptConverter.cs @@ -0,0 +1,109 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt; + +public class KitchenReceiptConverter +{ + private readonly int _lineWidth; + private readonly int _BigLineWidth; + + public KitchenReceiptConverter(int lineWidth = 42, int bigLineWidth=22) + { + _BigLineWidth = bigLineWidth; + _lineWidth = lineWidth; + } + + public List ConvertToPrintCommands(KitchenReceipt kitchenReceipt) + { + var commands = new List(); + + // Header - Restaurant name in red + commands.Add(new PrintCommand(Center(kitchenReceipt.Title, true)) { IsRed = true , IsBig = true}); + commands.Add(new PrintCommand(CreateDashedLine())); + commands.Add(new PrintCommand("")); + + // Transaction info + string dateTimeLine = $"{kitchenReceipt.TransactionDateTime:dd-MMM-yy HH:mm} Nr.:{kitchenReceipt.ReceiptNumber}"; + commands.Add(new PrintCommand(Center(dateTimeLine, false))); + + string serverLine = $"{kitchenReceipt.WaiterName}"; + commands.Add(new PrintCommand(Center(serverLine, false))); + + string serverIdLine = $"{kitchenReceipt.WaiterId}"; + commands.Add(new PrintCommand(Center(serverIdLine, false))); + + string tableLine = $"Tisch: {kitchenReceipt.TableNumber}"; + commands.Add(new PrintCommand(Center(tableLine, true), true, true)); + + commands.Add(new PrintCommand(CreateDashedLine())); + + + + + // Gangs + + foreach (Gang gang in kitchenReceipt.Gangs) + { + + commands.Add(new PrintCommand(Center($"{gang.Id}. {gang.Name}", false)) { IsRed = true }); + foreach (var dish in gang.Dishes) + { + string dishLine = $"{dish.Number}x {dish.Name}"; + commands.Add(new PrintCommand(dishLine)); + } + } + + if (kitchenReceipt.Gangs.Count > 0) + { + commands.Add(new PrintCommand(CreateDashedLine())); + } + + foreach (var dish in kitchenReceipt.Dishes) + { + string dishLine = $"{dish.Number}x {dish.Name}"; + commands.Add(new PrintCommand(dishLine)); + } + + + commands.Add(new PrintCommand("")); + commands.Add(new PrintCommand(CreateDashedLine())); + commands.Add(new PrintCommand("")); + + //// Additional info section + //if (kitchenReceipt.AdditionalInfo != null && kitchenReceipt.AdditionalInfo.Count > 0) + //{ + // commands.Add(new PrintCommand(CreateAsterisksLine())); + // commands.Add(new PrintCommand("Info über zugehörige Artikel")); + // commands.Add(new PrintCommand(CreateAsterisksLine())); + + // foreach (var info in kitchenReceipt.AdditionalInfo) + // { + // commands.Add(new PrintCommand(info)); + // } + + // commands.Add(new PrintCommand("")); + //} + + return commands; + } + + private string Center(string text, bool isBigFont) + { + var actualLineWidth = isBigFont ? _BigLineWidth : _lineWidth; + if (string.IsNullOrEmpty(text) || text.Length >= actualLineWidth) + return text; + + int totalPadding = actualLineWidth - text.Length; + int leftPadding = totalPadding / 2; + + return new string(' ', leftPadding) + text; + } + + private string CreateDashedLine() + { + return new string('-', _lineWidth); + } + + private string CreateAsterisksLine() + { + return new string('*', _lineWidth); + } +} diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs new file mode 100644 index 0000000..b9dde67 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceipt/Models.cs @@ -0,0 +1,92 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt +{ + /// + /// Represents a restaurant receipt from Warme Küche + /// + public class KitchenReceipt + { + /// + /// Restaurant name + /// + public string Title { get; set; } + + /// + /// Date and time of the transaction + /// + public DateTime TransactionDateTime { get; set; } + + /// + /// Receipt number + /// + public string ReceiptNumber { get; set; } + + /// + /// Server/Waiter name + /// + public string WaiterName { get; set; } + + /// + /// Server/Waiter ID + /// + public string WaiterId { get; set; } + + /// + /// Table number + /// + public int TableNumber { get; set; } + + + public List Gangs { get; set; } = new List(); + + public List Dishes { get; set; } = new List(); + + /// + /// Additional items or notes (e.g., "Amuse Bouche") + /// + public List AdditionalInfo { get; set; } + + public KitchenReceipt() + { + Gangs = new List(); + AdditionalInfo = new List(); + } + } + + + public class Gang + { + public Gang(int id, string name) + { + Id = id; + Name = name; + } + + public int Id { get; set; } + public string Name { get; set; } + public List Dishes { get; set; } = new List(); + } + + /// + /// Represents a dish item on the receipt + /// + public class Dish + { + /// + /// Number ordered + /// + public int Number { get; set; } + + /// + /// Name of the dish + /// + public string Name { get; set; } + + public Dish(int number, string name) + { + Number = number; + Name = name; + } + } + + +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceiptPrinter.cs b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceiptPrinter.cs index 950371c..8cbec8c 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceiptPrinter.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/KitchenReceiptPrinter.cs @@ -11,7 +11,7 @@ public class KitchenReceiptPrinter _bigFontLineWidth = bigFontLineWidth; } - public List ConvertToCommands(KitchenReceipt receipt) + public List ConvertToCommands(TranslatedKitchenReceipt receipt) { var commands = new List(); diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/PrintCommand.cs b/Inspectron.Epson/PrintServer/Printers/Utils/PrintCommand.cs new file mode 100644 index 0000000..0424012 --- /dev/null +++ b/Inspectron.Epson/PrintServer/Printers/Utils/PrintCommand.cs @@ -0,0 +1,16 @@ +namespace Inspectron.Epson.PrintServer.Printers.Utils; + +public class PrintCommand +{ + public string Text { get; set; } + public bool IsBig { get; set; } + public bool IsBold { get; set; } + public bool IsRed { get; set; } + + public PrintCommand(string text, bool isBig = false, bool isBold = false) + { + Text = text; + IsBig = isBig; + IsBold = isBold; + } +} \ No newline at end of file diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptTranslator.cs b/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptTranslator.cs index 5ce3283..15ddc50 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptTranslator.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptTranslator.cs @@ -1,7 +1,7 @@ namespace Inspectron.Epson.PrintServer.Printers.Utils; -public record KitchenReceipt(string Location, string Date, string Owner, string Tisch, List items) :ASTNode; +public record TranslatedKitchenReceipt(string Location, string Date, string Owner, string Tisch, List items) :ASTNode; public record KitchenItem(string Name) : ASTNode; public record KitchenProduct(int Amount, string Name) : KitchenItem(Name); public record KitchenGang(string Name) : KitchenItem(Name); @@ -112,7 +112,7 @@ public class ReceiptTranslator return new FinalReceipt(location, phone, url, date, items, total, mwst, comment, thanks); } - public static KitchenReceipt ParseKitchenReceipt(string receiptText) + public static TranslatedKitchenReceipt ParseKitchenReceipt(string receiptText) { var lines = receiptText.Split('\n', StringSplitOptions.RemoveEmptyEntries) .Select(l => l.Trim()) @@ -198,7 +198,7 @@ public class ReceiptTranslator currentIndex++; } - return new KitchenReceipt(location, date, owner, tisch, items); + return new TranslatedKitchenReceipt(location, date, owner, tisch, items); } diff --git a/Inspectron.Epson/PrintServer/WorkAreaSources/JamesWorkAreaSource.cs b/Inspectron.Epson/PrintServer/WorkAreaSources/JamesWorkAreaSource.cs index 13c2f83..bfec0ca 100644 --- a/Inspectron.Epson/PrintServer/WorkAreaSources/JamesWorkAreaSource.cs +++ b/Inspectron.Epson/PrintServer/WorkAreaSources/JamesWorkAreaSource.cs @@ -21,7 +21,7 @@ public class JamesWorkAreaSource: IWorkAreasSource response.Add(new WorkArea() { Id = "print-receipt", - Name = "Receipt" + Name = "FinalReceipt" }); return response!; } diff --git a/Screenshot 2025-12-14 201821_0bd9ce17.png b/Screenshot 2025-12-14 201821_0bd9ce17.png deleted file mode 100644 index 710de65875c8af5c4b41c4918a409f8dfedd18ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10057 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 #;sbo#njy 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

7%Ug)~> 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