Initial commit
Initial commit til Git. V2 er deployed
12
PointOfSale/Pos.Ui/Database/.config/dotnet-tools.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.9",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
16
PointOfSale/Pos.Ui/Database/Database.csproj
Normal file
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
60
PointOfSale/Pos.Ui/Database/LoadConfig.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Pos
|
||||
{
|
||||
public class LoadConfig
|
||||
{
|
||||
private string dir;
|
||||
public LoadConfig()
|
||||
{
|
||||
dir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
public IConfiguration ByEnvironment()
|
||||
{
|
||||
//Console.Out.WriteLine($"Json path: {dir}");
|
||||
#if DEBUG
|
||||
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
|
||||
#else
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
#endif
|
||||
//Running in a environment that not is supported in this setup
|
||||
throw new Exception("HostingEnvironment is not supported! This config setup only supports Development or Production");
|
||||
}
|
||||
|
||||
public IConfiguration DebugConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
|
||||
public IConfiguration ReleaseConfiguration()
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.SetBasePath(dir)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
|
||||
.Build();
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
PointOfSale/Pos.Ui/Database/Models/EmployeeEntity.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("employee")]
|
||||
public class EmployeeEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public bool IsModified { get; set; }
|
||||
}
|
||||
}
|
||||
21
PointOfSale/Pos.Ui/Database/Models/PaymentEntity.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("payment")]
|
||||
public class PaymentEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public int SaleId { get; set; }
|
||||
public decimal Amount { get; set;}
|
||||
public string Type { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
22
PointOfSale/Pos.Ui/Database/Models/ProductEntity.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("product")]
|
||||
public class ProductEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public int Index { get; set; }
|
||||
public bool IsModified { get; set; }
|
||||
public int ProductGroupId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(ProductGroupId))]
|
||||
public ProductGroupEntity ProductGroup { get; set; }
|
||||
}
|
||||
}
|
||||
22
PointOfSale/Pos.Ui/Database/Models/ProductGroupEntity.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("productgroup")]
|
||||
public class ProductGroupEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsArchived { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
public ICollection<ProductEntity> Products { get; set; }
|
||||
}
|
||||
}
|
||||
20
PointOfSale/Pos.Ui/Database/Models/SaleEntity.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("sale")]
|
||||
public class SaleEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
public int EmployeeId { get; set; }
|
||||
public bool IsModified { get; set; }
|
||||
}
|
||||
}
|
||||
22
PointOfSale/Pos.Ui/Database/Models/SaleLineEntity.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Models
|
||||
{
|
||||
[Table("sale_line")]
|
||||
public class SaleLineEntity
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public int SaleId { get; set; }
|
||||
public string Product { get; set; }
|
||||
public int Pieces { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public decimal Total { get; set; }
|
||||
}
|
||||
}
|
||||
35
PointOfSale/Pos.Ui/Database/PosDbContext.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pos;
|
||||
|
||||
|
||||
namespace Database
|
||||
{
|
||||
public class PosDbContext : DbContext
|
||||
{
|
||||
|
||||
public DbSet<EmployeeEntity> Employee { get; set; }
|
||||
public DbSet<ProductGroupEntity> ProductGroups { get; set; }
|
||||
public DbSet<ProductEntity> Products { get; set; }
|
||||
public DbSet<SaleEntity> Sales { get; set; }
|
||||
public DbSet<SaleLineEntity> SalesLines { get; set; }
|
||||
public DbSet<PaymentEntity> Payment { get; set; }
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
LoadConfig l = new LoadConfig();
|
||||
IConfiguration config = l.ByEnvironment();
|
||||
string connectionString = config["MariaSqlServer"].ToString();
|
||||
optionsBuilder
|
||||
.UseMySql(connectionString,ServerVersion.AutoDetect(connectionString))
|
||||
.UseLoggerFactory(LoggerFactory.Create(b => b
|
||||
.AddFilter(level => level >= LogLevel.Information)))
|
||||
.EnableSensitiveDataLogging()
|
||||
.EnableDetailedErrors();
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
PointOfSale/Pos.Ui/Database/Repository/EmployeeRepository.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Database.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class EmployeeRepository : IDisposable
|
||||
{
|
||||
|
||||
public void Add(string name)
|
||||
{
|
||||
EmployeeEntity employee = new EmployeeEntity();
|
||||
employee.Name = name;
|
||||
employee.IsModified = true;
|
||||
using PosDbContext context = new PosDbContext();
|
||||
context.Employee.Add(employee);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public EmployeeEntity Get(int employeeId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
EmployeeEntity employeeEntity = context.Employee.First(c => c.Id == employeeId);
|
||||
return employeeEntity;
|
||||
}
|
||||
|
||||
public List<EmployeeEntity> GetAll()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<EmployeeEntity> staffs = context.Employee.Where(c => c.IsArchived == false).ToList();
|
||||
|
||||
return staffs;
|
||||
}
|
||||
|
||||
public void Edit(int id, string name)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
EmployeeEntity employee = context.Employee.Single(c => c.Id == id);
|
||||
employee.Name = name;
|
||||
employee.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
EmployeeEntity employee = context.Employee.Single(c => c.Id == id);
|
||||
employee.IsArchived = true;
|
||||
employee.IsModified = true;
|
||||
context.SaveChanges();
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class ProductGroupRepository
|
||||
{
|
||||
public List<ProductGroupEntity> GetAll()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<ProductGroupEntity> productGroups = context.ProductGroups
|
||||
.Include(c => c.Products)
|
||||
.Where(c => c.IsArchived == false)
|
||||
.OrderBy(c => c.Index)
|
||||
.ToList();
|
||||
return productGroups;
|
||||
}
|
||||
|
||||
public ProductGroupEntity Get(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity product = context.ProductGroups.Single(c => c.Id == id);
|
||||
return product;
|
||||
}
|
||||
|
||||
public void Add(string name)
|
||||
{
|
||||
ProductGroupEntity productGroup = new ProductGroupEntity();
|
||||
productGroup.Name = name;
|
||||
using PosDbContext context = new PosDbContext();
|
||||
//Get the highest index
|
||||
ProductGroupEntity highest = context.ProductGroups.OrderByDescending(c => c.Index).Take(1).FirstOrDefault();
|
||||
if(highest == null)
|
||||
{
|
||||
highest = new ProductGroupEntity();
|
||||
highest.Index = 0;
|
||||
}
|
||||
productGroup.Index = highest.Index + 1;
|
||||
context.ProductGroups.Add(productGroup);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Edit(string name, int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity productGroup = context.ProductGroups.Single(c => c.Id == id);
|
||||
productGroup.Name = name;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Archive(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity productGroup = context.ProductGroups.Single(c => c.Id == id);
|
||||
productGroup.IsArchived = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void SetIndex(int id, int index)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductGroupEntity productGroup = context.ProductGroups.Single(c => c.Id == id);
|
||||
productGroup.Index = index;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public bool Any()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
bool any = context.ProductGroups.Any();
|
||||
return any;
|
||||
}
|
||||
}
|
||||
}
|
||||
87
PointOfSale/Pos.Ui/Database/Repository/ProductRepository.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Database.Models;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class ProductRepository
|
||||
{
|
||||
public List<ProductEntity> GetAll()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<ProductEntity> products = context.Products
|
||||
.Where(c => c.IsArchived == false)
|
||||
.OrderBy(c => c.Index)
|
||||
.ToList();
|
||||
return products;
|
||||
}
|
||||
|
||||
public List<ProductEntity> GetByProductGroup(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<ProductEntity> products = context.Products
|
||||
.Where(c => c.ProductGroupId == id)
|
||||
.Where(c => c.IsArchived == false)
|
||||
.OrderBy(c => c.Index)
|
||||
.ToList();
|
||||
return products;
|
||||
}
|
||||
|
||||
public void SetIndex(int id, int index)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity product = context.Products.Single(c => c.Id == id);
|
||||
product.Index = index;
|
||||
product.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public ProductEntity GetById(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity product = context.Products.Single(c => c.Id == id);
|
||||
return product;
|
||||
}
|
||||
|
||||
public void Update(int id, int productGroupId, string name)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity dbProduct = context.Products.Single(c => c.Id == id);
|
||||
dbProduct.ProductGroupId = productGroupId;
|
||||
dbProduct.Name = name;
|
||||
dbProduct.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Archive(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
ProductEntity dbProduct = context.Products.Single(c => c.Id == id);
|
||||
dbProduct.IsArchived = true;
|
||||
dbProduct.IsModified = true;
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public void Add(string name, int productGroupId)
|
||||
{
|
||||
|
||||
ProductEntity product = new ProductEntity();
|
||||
product.Name = name;
|
||||
product.ProductGroupId = productGroupId;
|
||||
using PosDbContext context = new PosDbContext();
|
||||
//Get the highest index
|
||||
ProductEntity highest = context.Products.OrderByDescending(c => c.Index).Take(1).FirstOrDefault();
|
||||
if (highest == null)
|
||||
{
|
||||
highest = new ProductEntity();
|
||||
highest.Index = 0;
|
||||
}
|
||||
product.Index = highest.Index + 1;
|
||||
product.IsModified = true;
|
||||
context.Products.Add(product);
|
||||
context.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
83
PointOfSale/Pos.Ui/Database/Repository/SaleRepository.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Database.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Database.Repository
|
||||
{
|
||||
public class SaleRepository
|
||||
{
|
||||
public SaleEntity New(int employeeId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
SaleEntity saleEntity = new SaleEntity();
|
||||
saleEntity.Time = DateTime.Now;
|
||||
saleEntity.EmployeeId = employeeId;
|
||||
saleEntity.IsModified = true;
|
||||
context.Sales.Add(saleEntity);
|
||||
context.SaveChanges();
|
||||
return saleEntity;
|
||||
}
|
||||
|
||||
public SaleLineEntity SaveSaleLine(SaleLineEntity entity)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
context.SalesLines.Add(entity);
|
||||
context.SaveChanges();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public List<SaleLineEntity> GetSaleLineBySaleId(int saleId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<SaleLineEntity> saleLineEntities = context.SalesLines.Where(c => c.SaleId == saleId).ToList();
|
||||
return saleLineEntities;
|
||||
}
|
||||
|
||||
public PaymentEntity SavePayment(PaymentEntity entity)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
context.Payment.Add(entity);
|
||||
context.SaveChanges();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public List<PaymentEntity> GetPaymentBySaleId(int saleId)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<PaymentEntity> paymentEntities = context.Payment.Where(c => c.SaleId == saleId).ToList();
|
||||
return paymentEntities;
|
||||
}
|
||||
|
||||
public SaleEntity GetLatest()
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
SaleEntity saleEntity = context.Sales.OrderByDescending(c => c.Id).Take(1).First();
|
||||
return saleEntity;
|
||||
}
|
||||
|
||||
public SaleEntity Get(int id)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
SaleEntity saleEntity = context.Sales.Single(c => c.Id == id);
|
||||
return saleEntity;
|
||||
}
|
||||
|
||||
public List<SaleEntity> GetByDateRange(DateTime start, DateTime end)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<SaleEntity> saleEntities = context.Sales.Where(c => c.Time.Date >= start.Date && c.Time.Date <= end.Date).OrderByDescending(c => c.Time).ToList();
|
||||
return saleEntities;
|
||||
}
|
||||
|
||||
public List<SaleEntity> GetByDateRange(DateTime start)
|
||||
{
|
||||
using PosDbContext context = new PosDbContext();
|
||||
List<SaleEntity> saleEntities = context.Sales.Where(c => c.Time.Date == start.Date.Date).OrderByDescending(c => c.Time).ToList();
|
||||
return saleEntities;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using EpsonPrinter.Services;
|
||||
|
||||
namespace EpsonPrinter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PosPrinterController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// PrintReceipt receipt, so far only for all Epson Thermal Printers
|
||||
/// </summary>
|
||||
/// PrintStyle is:
|
||||
/// None
|
||||
/// FontB
|
||||
/// Bold
|
||||
/// DoubleHeight
|
||||
/// DoubleWidth
|
||||
/// Underline
|
||||
/// There is support for any combination of PrintStyles
|
||||
/// ----------------------------------------
|
||||
///
|
||||
///
|
||||
/// <param name="receiptModel"></param>
|
||||
[HttpPost]
|
||||
[Route("Receipt")]
|
||||
public void PrintReceipt([FromServices] EpsonPrintService epsonPrint, ReceiptModel receiptModel)
|
||||
{
|
||||
epsonPrint.PrintReceipt(receiptModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("SaleOfDay")]
|
||||
public void PrintSaleOfDay([FromServices] EpsonPrintService epsonPrint, SaleOfDayModel saleOfDayModel)
|
||||
{
|
||||
epsonPrint.PrintSaleOfDay(saleOfDayModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EpsonPrinter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ValuesController : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[Route("HelloWorld")]
|
||||
public string Get()
|
||||
{
|
||||
return "HelloWorld";
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master.zip
Normal file
1
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
12
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: ['lukevp']
|
||||
#patreon: # Replace with a single Patreon username
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
7
PointOfSale/Pos.Ui/EpsonPrinter/ESC-POS/ESC-POS-.NET-master/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.vs/
|
||||
.idea/
|
||||
**/obj/
|
||||
**/bin/
|
||||
push.ps1
|
||||
/push.txt
|
||||
/ESCPOS_NET/ESCPOS_NET.csproj.user
|
||||
@@ -0,0 +1,74 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ESCPOS_NET\ESCPOS_NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="abe-lincoln.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\abe-lincoln.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\kitten.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-100.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-200.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.bmp">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.gif">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-300.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-400.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-500.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo-600.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\pd-logo.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="images\Portal_Companion_Cube.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="kitten.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="pd-logo.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="test-files\output-juliogamasso.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,267 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static BasePrinter printer;
|
||||
private static ICommandEmitter e;
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
|
||||
Console.WriteLine("Welcome to the ESCPOS_NET Test Application!");
|
||||
Console.Write("Would you like to see all debug messages? (y/n): ");
|
||||
var response = Console.ReadLine().Trim().ToLowerInvariant();
|
||||
var logLevel = LogLevel.Information;
|
||||
if (response.Length >= 1 && response[0] == 'y')
|
||||
{
|
||||
Console.WriteLine("Debugging enabled!");
|
||||
logLevel = LogLevel.Trace;
|
||||
}
|
||||
var factory = LoggerFactory.Create(b => b.AddConsole().SetMinimumLevel(logLevel));
|
||||
var logger = factory.CreateLogger<Program>();
|
||||
ESCPOS_NET.Logging.Logger = logger;
|
||||
|
||||
Console.WriteLine("1 ) Test Serial Port");
|
||||
Console.WriteLine("2 ) Test Network Printer");
|
||||
Console.Write("Choice: ");
|
||||
string comPort = "";
|
||||
string baudRate;
|
||||
string ip;
|
||||
string networkPort;
|
||||
response = Console.ReadLine();
|
||||
var valid = new List<string> { "1", "2" };
|
||||
if (!valid.Contains(response))
|
||||
{
|
||||
response = "1";
|
||||
}
|
||||
|
||||
int choice = int.Parse(response);
|
||||
|
||||
if (choice == 1)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
while (!comPort.StartsWith("COM"))
|
||||
{
|
||||
Console.Write("COM Port (enter for default COM5): ");
|
||||
comPort = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(comPort))
|
||||
{
|
||||
comPort = "COM5";
|
||||
}
|
||||
}
|
||||
Console.Write("Baud Rate (enter for default 115200): ");
|
||||
baudRate = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(baudRate))
|
||||
{
|
||||
baudRate = "115200";
|
||||
}
|
||||
printer = new SerialPrinter(portName: comPort, baudRate: 115200);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
Console.Write("File / virtual com path (eg. /dev/usb/lp0): ");
|
||||
comPort = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(comPort))
|
||||
{
|
||||
comPort = "/dev/usb/lp0";
|
||||
}
|
||||
printer = new FilePrinter(filePath: comPort, false);
|
||||
}
|
||||
}
|
||||
else if (choice == 2)
|
||||
{
|
||||
Console.Write("IP Address (eg. 192.168.1.240): ");
|
||||
ip = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(ip))
|
||||
{
|
||||
ip = "192.168.254.202";
|
||||
}
|
||||
Console.Write("TCP Port (enter for default 9100): ");
|
||||
networkPort = Console.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(networkPort))
|
||||
{
|
||||
networkPort = "9100";
|
||||
}
|
||||
printer = new NetworkPrinter(settings: new NetworkPrinterSettings() { ConnectionString = $"{ip}:{networkPort}" });
|
||||
}
|
||||
|
||||
bool monitor = false;
|
||||
Thread.Sleep(500);
|
||||
Console.Write("Turn on Live Status Back Monitoring? (y/n): ");
|
||||
response = Console.ReadLine().Trim().ToLowerInvariant();
|
||||
if (response.Length >= 1 && response[0] == 'y')
|
||||
{
|
||||
monitor = true;
|
||||
}
|
||||
|
||||
e = new EPSON();
|
||||
var testCases = new Dictionary<Option, string>()
|
||||
{
|
||||
{ Option.SingleLinePrinting, "Single Line Printing" },
|
||||
{ Option.MultiLinePrinting, "Multi-line Printing" },
|
||||
{ Option.LineSpacing, "Line Spacing" },
|
||||
{ Option.BarcodeStyles, "Barcode Styles" },
|
||||
{ Option.BarcodeTypes, "Barcode Types" },
|
||||
{ Option.TwoDimensionCodes, "2D Codes" },
|
||||
{ Option.TextStyles, "Text Styles" },
|
||||
{ Option.FullReceipt, "Full Receipt" },
|
||||
{ Option.CodePages, "Code Pages (Euro, Katakana, Etc)" },
|
||||
{ Option.Images, "Images" },
|
||||
{ Option.LegacyImages, "Legacy Images" },
|
||||
{ Option.LargeByteArrays, "Large Byte Arrays" },
|
||||
{ Option.CashDrawerPin2, "Cash Drawer Pin2" },
|
||||
{ Option.CashDrawerPin5, "Cash Drawer Pin5" },
|
||||
{ Option.Exit, "Exit" }
|
||||
|
||||
};
|
||||
while (true)
|
||||
{
|
||||
foreach (var item in testCases)
|
||||
{
|
||||
Console.WriteLine($"{(int)item.Key} : {item.Value}");
|
||||
}
|
||||
Console.Write("Execute Test: ");
|
||||
|
||||
if (!int.TryParse(Console.ReadLine(), out choice) || !Enum.IsDefined(typeof(Option), choice))
|
||||
{
|
||||
Console.WriteLine("Invalid entry. Please try again.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var enumChoice = (Option)choice;
|
||||
if (enumChoice == Option.Exit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Clear();
|
||||
|
||||
if (monitor)
|
||||
{
|
||||
printer.Write(e.Initialize());
|
||||
printer.Write(e.Enable());
|
||||
printer.Write(e.EnableAutomaticStatusBack());
|
||||
}
|
||||
Setup(monitor);
|
||||
|
||||
printer?.Write(e.PrintLine($"== [ Start {testCases[enumChoice]} ] =="));
|
||||
|
||||
switch (enumChoice)
|
||||
{
|
||||
case Option.SingleLinePrinting:
|
||||
printer.Write(Tests.SingleLinePrinting(e));
|
||||
break;
|
||||
case Option.MultiLinePrinting:
|
||||
printer.Write(Tests.MultiLinePrinting(e));
|
||||
break;
|
||||
case Option.LineSpacing:
|
||||
printer.Write(Tests.LineSpacing(e));
|
||||
break;
|
||||
case Option.BarcodeStyles:
|
||||
printer.Write(Tests.BarcodeStyles(e));
|
||||
break;
|
||||
case Option.BarcodeTypes:
|
||||
printer.Write(Tests.BarcodeTypes(e));
|
||||
break;
|
||||
case Option.TwoDimensionCodes:
|
||||
printer.Write(Tests.TwoDimensionCodes(e));
|
||||
break;
|
||||
case Option.TextStyles:
|
||||
printer.Write(Tests.TextStyles(e));
|
||||
break;
|
||||
case Option.FullReceipt:
|
||||
printer.Write(Tests.Receipt(e));
|
||||
break;
|
||||
case Option.Images:
|
||||
printer.Write(Tests.Images(e, false));
|
||||
break;
|
||||
case Option.LegacyImages:
|
||||
printer.Write(Tests.Images(e, true));
|
||||
break;
|
||||
case Option.LargeByteArrays:
|
||||
try
|
||||
{
|
||||
printer.Write(Tests.TestLargeByteArrays(e));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Aborting print due to test failure. Exception: {e?.Message}, Stack Trace: {e?.GetBaseException()?.StackTrace}");
|
||||
}
|
||||
break;
|
||||
case Option.CashDrawerPin2:
|
||||
printer.Write(Tests.CashDrawerOpenPin2(e));
|
||||
break;
|
||||
case Option.CashDrawerPin5:
|
||||
printer.Write(Tests.CashDrawerOpenPin5(e));
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid entry.");
|
||||
break;
|
||||
}
|
||||
|
||||
Setup(monitor);
|
||||
printer?.Write(e.PrintLine($"== [ End {testCases[enumChoice]} ] =="));
|
||||
printer?.Write(e.PartialCutAfterFeed(5));
|
||||
|
||||
// TODO: also make an automatic runner that runs all tests (command line).
|
||||
}
|
||||
}
|
||||
|
||||
public enum Option
|
||||
{
|
||||
SingleLinePrinting = 1,
|
||||
MultiLinePrinting,
|
||||
LineSpacing,
|
||||
BarcodeStyles,
|
||||
BarcodeTypes,
|
||||
TwoDimensionCodes,
|
||||
TextStyles,
|
||||
FullReceipt,
|
||||
CodePages,
|
||||
Images,
|
||||
LegacyImages,
|
||||
LargeByteArrays,
|
||||
CashDrawerPin2,
|
||||
CashDrawerPin5,
|
||||
Exit = 99
|
||||
}
|
||||
|
||||
private static void StatusChanged(object sender, EventArgs ps)
|
||||
{
|
||||
var status = (PrinterStatusEventArgs)ps;
|
||||
if (status == null) { Console.WriteLine("Status was null - unable to read status from printer."); return; }
|
||||
Console.WriteLine($"Printer Online Status: {status.IsPrinterOnline}");
|
||||
Console.WriteLine(JsonConvert.SerializeObject(status));
|
||||
}
|
||||
private static bool _hasEnabledStatusMonitoring = false;
|
||||
|
||||
private static void Setup(bool enableStatusBackMonitoring)
|
||||
{
|
||||
if (printer != null)
|
||||
{
|
||||
// Only register status monitoring once.
|
||||
if (!_hasEnabledStatusMonitoring)
|
||||
{
|
||||
printer.StatusChanged += StatusChanged;
|
||||
_hasEnabledStatusMonitoring = true;
|
||||
}
|
||||
printer?.Write(e.Initialize());
|
||||
printer?.Write(e.Enable());
|
||||
if (enableStatusBackMonitoring)
|
||||
{
|
||||
printer.Write(e.EnableAutomaticStatusBack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
private const string websiteString = "https://github.com/lukevp/ESC-POS-.NET/";
|
||||
public static byte[][] TwoDimensionCodes(ICommandEmitter e) => new byte[][] {
|
||||
e.PrintLine("PDF417:"),
|
||||
e.Print2DCode(TwoDimensionCodeType.PDF417, websiteString),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("PDF417 (TINY):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.PDF417, websiteString, Size2DCode.TINY),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("PDF417 (LARGE):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.PDF417, websiteString, Size2DCode.LARGE),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 1:"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MODEL1, websiteString),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 2:"),
|
||||
e.PrintQRCode(websiteString),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MICRO:"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MICRO, "github.com/lukevp"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 1 (TINY):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MODEL1, websiteString, Size2DCode.TINY),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("QRCODE MODEL 1 (LARGE):"),
|
||||
e.Print2DCode(TwoDimensionCodeType.QRCODE_MODEL1, websiteString, Size2DCode.LARGE),
|
||||
e.PrintLine()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] BarcodeStyles(ICommandEmitter e) => new byte[][] {
|
||||
//TODO: test all widths and put bar in front in label
|
||||
e.PrintLine("Thinnest Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thinnest),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Thin Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thin),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Default Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Default),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Thicker Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thick),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Thickest Width:"),
|
||||
e.SetBarcodeHeightInDots(300),
|
||||
e.SetBarWidth(BarWidth.Thickest),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
|
||||
e.PrintLine("Short (50 dots):"),
|
||||
e.SetBarcodeHeightInDots(50),
|
||||
e.SetBarWidth(BarWidth.Default),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Tall (255 dots):"),
|
||||
e.SetBarcodeHeightInDots(255),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Label Above:"),
|
||||
e.SetBarcodeHeightInDots(50),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Above),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Label Above and Below:"),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Both),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Label Below:"),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Below),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905"),
|
||||
|
||||
e.PrintLine("Font B Label Below:"),
|
||||
e.SetBarLabelFontB(true),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "012345678905")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] BarcodeTypes(ICommandEmitter e) => new byte[][] {
|
||||
e.SetBarcodeHeightInDots(600),
|
||||
e.SetBarWidth(BarWidth.Thinnest),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.Below),
|
||||
|
||||
e.PrintLine("CODABAR_NW_7:"),
|
||||
e.PrintBarcode(BarcodeType.CODABAR_NW_7, "A31117013206375B"),
|
||||
|
||||
e.PrintLine("CODE128:"),
|
||||
e.PrintBarcode(BarcodeType.CODE128, "ESC_POS_NET"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("CODE128 Type C:"),
|
||||
e.PrintBarcode(BarcodeType.CODE128, "123456789101", BarcodeCode.CODE_C),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("CODE39:"),
|
||||
e.PrintBarcode(BarcodeType.CODE39, "*ESC-POS-NET*"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("CODE93:"),
|
||||
e.PrintBarcode(BarcodeType.CODE93, "*ESC_POS_NET*"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("GS1_128:"),
|
||||
e.PrintBarcode(BarcodeType.GS1_128, "(01)9501234567890*"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("GS1_DATABAR_EXPANDED:"),
|
||||
e.PrintBarcode(BarcodeType.GS1_DATABAR_EXPANDED, "0001234567890"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("GS1_DATABAR_LIMITED:"),
|
||||
e.PrintBarcode(BarcodeType.GS1_DATABAR_LIMITED, "0001234567890"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("GS1_DATABAR_OMNIDIRECTIONAL:"),
|
||||
e.PrintBarcode(BarcodeType.GS1_DATABAR_OMNIDIRECTIONAL, "0001234567890"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("GS1_DATABAR_TRUNCATED:"),
|
||||
e.PrintBarcode(BarcodeType.GS1_DATABAR_TRUNCATED, "0001234567890"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("ITF:"),
|
||||
e.PrintBarcode(BarcodeType.ITF, "1234567895"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("JAN13_EAN13:"),
|
||||
e.PrintBarcode(BarcodeType.JAN13_EAN13, "5901234123457"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("JAN8_EAN8:"),
|
||||
e.PrintBarcode(BarcodeType.JAN8_EAN8, "96385074"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("UPC_A:"),
|
||||
e.PrintBarcode(BarcodeType.UPC_A, "042100005264"),
|
||||
e.PrintLine(),
|
||||
|
||||
e.PrintLine("UPC_E:"),
|
||||
e.PrintBarcode(BarcodeType.UPC_E, "425261"),
|
||||
e.PrintLine()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] CashDrawerOpenPin2(ICommandEmitter e) => new byte[][] {
|
||||
e.CashDrawerOpenPin2()
|
||||
};
|
||||
|
||||
public static byte[][] CashDrawerOpenPin5(ICommandEmitter e) => new byte[][] {
|
||||
e.CashDrawerOpenPin5()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] CodePages(ICommandEmitter e, CodePage codePage) {
|
||||
List<byte[]> test = new List<byte[]>();
|
||||
test.Add(e.LeftAlign());
|
||||
test.Add(e.PrintLine("Empty space = space or non-printable character."));
|
||||
test.Add(e.PrintLine("Each row represents the first hex digit."));
|
||||
test.Add(e.PrintLine("Each column represents the second hex digit."));
|
||||
test.Add(e.PrintLine("For example, row 7, column A, represents"));
|
||||
test.Add(e.PrintLine("the character with hex 0x7A."));
|
||||
test.Add(e.PrintLine());
|
||||
test.Add(e.PrintLine("Character Table for Code Page:"));
|
||||
test.Add(e.PrintLine(codePage + " (Page " + ((int)codePage) + ")"));
|
||||
test.Add(e.PrintLine("=========================="));
|
||||
test.Add(e.PrintLine());
|
||||
test.Add(e.PrintLine(" 0 1 2 3 4 5 6 7 8 9 A B C D E F "));
|
||||
// Set CodePage to test codepage.
|
||||
test.Add(e.CodePage(codePage));
|
||||
for (int d1 = 0; d1 < 0x10; d1++)
|
||||
{
|
||||
|
||||
var upperDigit = d1.ToString("x1").ToUpperInvariant();
|
||||
test.Add(e.Print(upperDigit + " "));
|
||||
for (int d2 = 0; d2 < 0x10; d2++)
|
||||
{
|
||||
var digit = d1 * 0x10 + d2;
|
||||
if (digit <= 0x20) digit = 0x20;
|
||||
test.Add(e.Print((char)digit + " "));
|
||||
}
|
||||
test.Add(e.PrintLine());
|
||||
}
|
||||
// Set CodePage back to default
|
||||
test.Add(e.CodePage(CodePage.PC437_USA_STANDARD_EUROPE_DEFAULT));
|
||||
test.Add(e.PrintLine());
|
||||
return test.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using System.IO;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] Images(ICommandEmitter e, bool isLegacy) => new byte[][] {
|
||||
e.CenterAlign(),
|
||||
e.PrintLine("Test PNG images with widths 100 - 600 px,"),
|
||||
e.PrintLine("at native resolution"),
|
||||
e.PrintLine("-- pd-logo-100.png --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-100.png"), true, isLegacy),
|
||||
e.PrintLine("-- pd-logo-200.png --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-200.png"), true, isLegacy),
|
||||
e.PrintLine("-- pd-logo-300.png --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy),
|
||||
e.PrintLine("-- pd-logo-400.png --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-400.png"), true, isLegacy),
|
||||
e.PrintLine("-- pd-logo-500.png --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-500.png"), true, isLegacy),
|
||||
e.PrintLine("-- pd-logo-600.png --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-600.png"), true, isLegacy),
|
||||
e.PrintLine("Test resizing 600 px image to 300px"),
|
||||
e.PrintLine("-- pd-logo-600.png /300 --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-600.png"), true, isLegacy, 300),
|
||||
e.PrintLine("Test image with taller height than width"),
|
||||
e.PrintLine("-- abe-lincoln.png /300 --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/abe-lincoln.png"), true, isLegacy, 300),
|
||||
e.PrintLine("Test 300px image resized to all remainders of 8,"),
|
||||
e.PrintLine("to ensure overflow checking"),
|
||||
e.PrintLine("-- pd-logo-300.png /296 (0 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 296),
|
||||
e.PrintLine("-- pd-logo-300.png /297 (1 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 297),
|
||||
e.PrintLine("-- pd-logo-300.png /298 (2 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 298),
|
||||
e.PrintLine("-- pd-logo-300.png /299 (3 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 299),
|
||||
e.PrintLine("-- pd-logo-300.png /300 (4 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 300),
|
||||
e.PrintLine("-- pd-logo-300.png /301 (5 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 301),
|
||||
e.PrintLine("-- pd-logo-300.png /302 (6 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 302),
|
||||
e.PrintLine("-- pd-logo-300.png /303 (7 remainder) --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true, isLegacy, 303),
|
||||
e.PrintLine("Test 300px image in JPG format"),
|
||||
e.PrintLine("-- pd-logo-300.jpg --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.jpg"), true, isLegacy),
|
||||
e.PrintLine("Test 300px image in BMP format"),
|
||||
e.PrintLine("-- pd-logo-300.jpg --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.bmp"), true, isLegacy),
|
||||
e.PrintLine("Test 300px image in GIF format"),
|
||||
e.PrintLine("-- pd-logo-300.jpg --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.gif"), true, isLegacy),
|
||||
e.PrintLine("Test full color image converted"),
|
||||
e.PrintLine("to black and white and interpolated"),
|
||||
e.PrintLine("-- kitten.jpg --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/kitten.jpg"), true, isLegacy, 500),
|
||||
e.PrintLine("-- portal companion cube.jpg --"),
|
||||
e.PrintImage(File.ReadAllBytes("images/Portal_Companion_Cube.jpg"), true, isLegacy, 500)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[] TestLargeByteArrays(ICommandEmitter e)
|
||||
{
|
||||
var kitten = e.PrintImage(File.ReadAllBytes("images/kitten.jpg"), true, true, 500);
|
||||
var cube = e.PrintImage(File.ReadAllBytes("images/Portal_Companion_Cube.jpg"), true, true, 500);
|
||||
var expectedResult = ByteSplicer.Combine(
|
||||
e.CenterAlign(),
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube,
|
||||
kitten,
|
||||
cube
|
||||
);
|
||||
MemoryPrinter mp = new MemoryPrinter();
|
||||
mp.Write(expectedResult);
|
||||
var response = mp.GetAllData();
|
||||
bool hasErrors = false;
|
||||
if (expectedResult.Length != response.Length)
|
||||
{
|
||||
Console.WriteLine($"Error: MemoryPrinter length mismatch - ${response.Length}, expected ${expectedResult.Length}");
|
||||
hasErrors = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < expectedResult.Length; i++)
|
||||
{
|
||||
if (expectedResult[i] != response[i])
|
||||
{
|
||||
Console.WriteLine($"Error: MemoryPrinter data mismatch - ${expectedResult[i]}, expected ${response[i]}, at location ${i}");
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasErrors)
|
||||
{
|
||||
Console.WriteLine("MemoryPrinter: ALL OK!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("MemoryPrinter: Errors occured during testing, aborting!");
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
Random r = new Random();
|
||||
var filename = $"{r.NextDouble().ToString()}.tmp";
|
||||
using (FilePrinter fp = new FilePrinter(filename, true))
|
||||
{
|
||||
fp.Write(expectedResult);
|
||||
}
|
||||
response = File.ReadAllBytes(filename);
|
||||
hasErrors = false;
|
||||
if (expectedResult.Length != response.Length)
|
||||
{
|
||||
Console.WriteLine($"Error: FilePrinter length mismatch - ${response.Length}, expected ${expectedResult.Length}");
|
||||
hasErrors = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < expectedResult.Length; i++)
|
||||
{
|
||||
if (expectedResult[i] != response[i])
|
||||
{
|
||||
Console.WriteLine($"Error: FilePrinter data mismatch - ${expectedResult[i]}, expected ${response[i]}, at location ${i}");
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasErrors)
|
||||
{
|
||||
Console.WriteLine("FilePrinter: ALL OK!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("FilePrinter: Errors occured during testing, aborting!");
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
return expectedResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] LineSpacing(ICommandEmitter e) => new byte[][] {
|
||||
e.SetLineSpacingInDots(200),
|
||||
e.PrintLine("This is the default spacing."),
|
||||
e.SetLineSpacingInDots(15),
|
||||
e.PrintLine("This has 200 dots of spacing above."),
|
||||
e.ResetLineSpacing(),
|
||||
e.PrintLine("This has 15 dots of spacing above."),
|
||||
e.PrintLine("This has the default spacing.")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] MultiLinePrinting(ICommandEmitter e) => new byte[][] {
|
||||
e.Print("Multiline Test: Windows...\r\nOSX...\rUnix...\n"),
|
||||
//TODO: sanitize test.
|
||||
e.PrintLine("Feeding 250 dots."),
|
||||
e.FeedDots(250),
|
||||
e.PrintLine("Feeding 3 lines."),
|
||||
e.FeedLines(3),
|
||||
e.PrintLine("Done Feeding."),
|
||||
e.PrintLine("Reverse Feeding 6 lines."),
|
||||
e.FeedLinesReverse(6),
|
||||
e.PrintLine("Done Reverse Feeding.")
|
||||
};
|
||||
|
||||
public static byte[][] SingleLinePrinting(ICommandEmitter e) => new byte[][] {
|
||||
e.Print("Single Test Line Of Text\r\n"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using System.IO;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] Receipt(ICommandEmitter e) => new byte[][] {
|
||||
e.CenterAlign(),
|
||||
e.PrintImage(File.ReadAllBytes("images/pd-logo-300.png"), true),
|
||||
e.PrintLine(),
|
||||
e.SetBarcodeHeightInDots(360),
|
||||
e.SetBarWidth(BarWidth.Default),
|
||||
e.SetBarLabelPosition(BarLabelPrintPosition.None),
|
||||
e.PrintBarcode(BarcodeType.ITF, "0123456789"),
|
||||
e.PrintLine("B&H PHOTO & VIDEO"),
|
||||
e.PrintLine("420 NINTH AVE."),
|
||||
e.PrintLine("NEW YORK, NY 10001"),
|
||||
e.PrintLine("(212) 502-6380 - (800)947-9975"),
|
||||
e.SetStyles(PrintStyle.Underline),
|
||||
e.PrintLine("www.bhphotovideo.com"),
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.PrintLine(),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine("Order: 123456789 Date: 02/01/19"),
|
||||
e.PrintLine(),
|
||||
e.PrintLine(),
|
||||
e.SetStyles(PrintStyle.FontB),
|
||||
e.PrintLine("1 TRITON LOW-NOISE IN-LINE MICROPHONE PREAMP"),
|
||||
e.PrintLine(" TRFETHEAD/FETHEAD 89.95 89.95"),
|
||||
e.PrintLine("----------------------------------------------------------------"),
|
||||
e.RightAlign(),
|
||||
e.PrintLine("SUBTOTAL 89.95"),
|
||||
e.PrintLine("Total Order: 89.95"),
|
||||
e.PrintLine("Total Payment: 89.95"),
|
||||
e.PrintLine(),
|
||||
e.LeftAlign(),
|
||||
e.SetStyles(PrintStyle.Bold | PrintStyle.FontB),
|
||||
e.PrintLine("SOLD TO: SHIP TO:"),
|
||||
e.SetStyles(PrintStyle.FontB),
|
||||
e.PrintLine(" LUKE PAIREEPINART LUKE PAIREEPINART"),
|
||||
e.PrintLine(" 123 FAKE ST. 123 FAKE ST."),
|
||||
e.PrintLine(" DECATUR, IL 12345 DECATUR, IL 12345"),
|
||||
e.PrintLine(" (123)456-7890 (123)456-7890"),
|
||||
e.PrintLine(" CUST: 87654321"),
|
||||
e.PrintLine(),
|
||||
e.PrintLine()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace ESCPOS_NET.ConsoleTest
|
||||
{
|
||||
|
||||
public static partial class Tests
|
||||
{
|
||||
public static byte[][] TextStyles(ICommandEmitter e) => new byte[][] {
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.Print("Default: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.FontB),
|
||||
e.Print("Font B: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.Bold),
|
||||
e.Print("Bold: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.Underline),
|
||||
e.Print("Underline: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.Print("DoubleWidth: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.DoubleHeight),
|
||||
e.Print("DoubleHeight: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.FontB | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.Underline | PrintStyle.Bold),
|
||||
e.Print("All Styles: The quick brown fox jumped over the lazy dogs.\n"),
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.ReverseMode(true),
|
||||
e.PrintLine("REVERSE MODE: The quick brown fox jumped over the lazy dogs."),
|
||||
e.SetStyles(PrintStyle.FontB | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth),
|
||||
e.PrintLine("REVERSE MODE: The quick brown fox jumped over the lazy dogs."),
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.ReverseMode(false),
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.RightCharacterSpacing(5),
|
||||
e.PrintLine("Right space 5: The quick brown fox jumped over the lazy dogs."),
|
||||
e.RightCharacterSpacing(0),
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.UpsideDownMode(true),
|
||||
e.PrintLine("Upside Down Mode: The quick brown fox jumped over the lazy dogs."),
|
||||
e.UpsideDownMode(false)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,172 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<svg
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:ns1="http://sozi.baierouge.fr"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
id="Layer_1"
|
||||
sodipodi:docname="public-domain-logo-slightly-nicer.svg"
|
||||
enable-background="new 0.995 1.495 88 31"
|
||||
xml:space="preserve"
|
||||
viewBox="0.995 1.495 671.6875 215.625"
|
||||
version="1.1"
|
||||
y="0px"
|
||||
x="0px"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
><sodipodi:namedview
|
||||
id="namedview43"
|
||||
fit-margin-left="0"
|
||||
inkscape:zoom="0.3"
|
||||
borderopacity="1"
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:cx="450.19344"
|
||||
inkscape:cy="-104.995"
|
||||
inkscape:window-maximized="1"
|
||||
showgrid="false"
|
||||
fit-margin-right="0"
|
||||
bordercolor="#666666"
|
||||
inkscape:window-x="0"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:window-y="24"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
pagecolor="#ffffff"
|
||||
gridtolerance="10"
|
||||
inkscape:window-height="1124"
|
||||
showborder="false"
|
||||
fit-margin-top="0"
|
||||
/>
|
||||
<g
|
||||
id="g4285"
|
||||
transform="translate(-224.16 380.12)"
|
||||
><rect
|
||||
id="rect3914-6"
|
||||
style="stroke-linejoin:round;fill-rule:evenodd;stroke:#000000;stroke-linecap:round;stroke-width:4.9835;fill:#ffffff"
|
||||
rx="16.992"
|
||||
ry="13.212"
|
||||
height="210.65"
|
||||
width="666.71"
|
||||
y="-376.14"
|
||||
x="227.64"
|
||||
/><path
|
||||
id="path11-9-3-7"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m411.62-355.34c25.35 19.694 41.867 51.242 41.874 86.922-0.008 32.459-13.679 61.507-35.231 81.323h457.33v-168.24h-463.97z"
|
||||
/><g
|
||||
id="g15-9-3-0"
|
||||
transform="matrix(8.4847 0 0 8.4847 226.81 -409.82)"
|
||||
><path
|
||||
id="path17-8-7-0"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m36.739 8.557c0.392 0 0.728 0.059 1.002 0.173 0.276 0.116 0.5 0.268 0.674 0.456 0.173 0.189 0.299 0.405 0.379 0.647 0.079 0.241 0.118 0.493 0.118 0.753 0 0.253-0.039 0.503-0.118 0.749-0.08 0.244-0.206 0.462-0.379 0.65-0.174 0.188-0.397 0.341-0.674 0.456-0.274 0.115-0.61 0.173-1.002 0.173h-1.452v2.267h-1.382v-6.324h2.834zm-0.379 2.976c0.158 0 0.312-0.012 0.457-0.035 0.147-0.023 0.276-0.069 0.388-0.137 0.111-0.068 0.201-0.164 0.269-0.288s0.101-0.287 0.101-0.487c0-0.201-0.033-0.363-0.101-0.488-0.067-0.123-0.157-0.22-0.269-0.286-0.111-0.069-0.24-0.114-0.388-0.138-0.146-0.024-0.299-0.036-0.457-0.036h-1.073v1.896l1.073-0.001z"
|
||||
/><path
|
||||
id="path19-2-5-5"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m44.751 14.398c-0.476 0.417-1.133 0.625-1.972 0.625-0.851 0-1.509-0.207-1.976-0.62-0.466-0.413-0.699-1.052-0.699-1.913v-3.933h1.381v3.934c0 0.171 0.016 0.339 0.045 0.506 0.029 0.165 0.091 0.311 0.185 0.438 0.094 0.125 0.225 0.229 0.392 0.309s0.392 0.119 0.673 0.119c0.493 0 0.833-0.109 1.021-0.332 0.188-0.221 0.282-0.568 0.282-1.04v-3.934h1.382v3.934c-0.001 0.855-0.239 1.491-0.714 1.907z"
|
||||
/><path
|
||||
id="path21-0-4-6"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m50.069 8.557c0.301 0 0.572 0.027 0.817 0.081 0.246 0.053 0.459 0.14 0.636 0.26 0.176 0.121 0.312 0.282 0.407 0.483 0.099 0.201 0.146 0.45 0.146 0.745 0 0.318-0.071 0.584-0.217 0.796-0.144 0.212-0.355 0.388-0.637 0.522 0.387 0.112 0.676 0.309 0.865 0.589 0.191 0.281 0.286 0.619 0.286 1.015 0 0.319-0.062 0.595-0.185 0.829-0.123 0.232-0.289 0.422-0.498 0.57-0.207 0.148-0.445 0.257-0.713 0.328-0.269 0.07-0.541 0.105-0.822 0.105h-3.044v-6.323h2.959zm-0.173 2.56c0.246 0 0.447-0.059 0.606-0.178 0.157-0.118 0.237-0.309 0.237-0.576 0-0.147-0.026-0.269-0.08-0.362-0.053-0.095-0.122-0.168-0.211-0.222-0.088-0.053-0.188-0.09-0.303-0.109-0.115-0.022-0.233-0.032-0.356-0.032h-1.294v1.479h1.401zm0.078 2.685c0.135 0 0.264-0.014 0.387-0.04 0.125-0.026 0.231-0.072 0.326-0.133 0.094-0.062 0.168-0.147 0.227-0.254 0.056-0.104 0.083-0.241 0.083-0.406 0-0.325-0.093-0.557-0.271-0.696-0.184-0.138-0.425-0.208-0.724-0.208h-1.505v1.737h1.477z"
|
||||
/><path
|
||||
id="path23-9-1-0"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m55.142 8.557v5.155h3.062v1.169h-4.444v-6.324h1.382z"
|
||||
/><path
|
||||
id="path25-4-8-8"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m60.748 8.557v6.324h-1.382v-6.324h1.382z"
|
||||
/><path
|
||||
id="path27-9-0-7"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m66.45 10.244c-0.082-0.132-0.184-0.248-0.307-0.349-0.125-0.101-0.265-0.179-0.421-0.235-0.153-0.057-0.315-0.085-0.487-0.085-0.312 0-0.574 0.062-0.791 0.183-0.217 0.12-0.396 0.283-0.527 0.486-0.137 0.204-0.232 0.436-0.296 0.695-0.062 0.26-0.093 0.529-0.093 0.806 0 0.267 0.031 0.525 0.093 0.776s0.159 0.477 0.296 0.677c0.134 0.201 0.311 0.361 0.527 0.483 0.217 0.12 0.479 0.181 0.791 0.181 0.424 0 0.754-0.129 0.99-0.389s0.383-0.602 0.437-1.028h1.337c-0.034 0.396-0.126 0.753-0.271 1.072-0.146 0.318-0.34 0.591-0.58 0.815s-0.521 0.395-0.846 0.513c-0.322 0.119-0.678 0.178-1.064 0.178-0.48 0-0.914-0.084-1.299-0.252-0.383-0.17-0.709-0.399-0.972-0.696-0.265-0.295-0.468-0.641-0.606-1.04-0.143-0.399-0.213-0.829-0.213-1.29 0-0.472 0.07-0.91 0.213-1.314 0.141-0.404 0.344-0.757 0.606-1.058 0.263-0.302 0.589-0.537 0.972-0.709 0.385-0.172 0.816-0.258 1.299-0.258 0.347 0 0.675 0.051 0.98 0.15 0.309 0.102 0.583 0.248 0.827 0.439 0.243 0.191 0.444 0.43 0.603 0.713 0.16 0.283 0.258 0.608 0.301 0.974h-1.339c-0.024-0.159-0.078-0.305-0.16-0.438z"
|
||||
/><path
|
||||
id="path29-7-0-4"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m36.615 17.415c0.405 0 0.782 0.064 1.131 0.193 0.35 0.131 0.651 0.326 0.906 0.586s0.455 0.584 0.599 0.975c0.144 0.389 0.216 0.848 0.216 1.372 0 0.462-0.059 0.888-0.176 1.274-0.118 0.391-0.295 0.728-0.532 1.012-0.238 0.283-0.534 0.506-0.89 0.668-0.354 0.162-0.772 0.244-1.254 0.244h-2.71v-6.324h2.71zm-0.096 5.154c0.199 0 0.393-0.031 0.581-0.097s0.354-0.174 0.502-0.323c0.146-0.151 0.264-0.349 0.352-0.59 0.088-0.242 0.132-0.537 0.132-0.887 0-0.316-0.031-0.605-0.093-0.863-0.062-0.257-0.162-0.478-0.304-0.658-0.141-0.186-0.326-0.324-0.559-0.422-0.231-0.099-0.517-0.146-0.858-0.146h-0.984v3.984h1.231v0.002z"
|
||||
/><path
|
||||
id="path31-9-8-2"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m40.8 19.289c0.141-0.405 0.344-0.759 0.606-1.06 0.265-0.304 0.589-0.537 0.973-0.709 0.385-0.172 0.816-0.258 1.298-0.258 0.487 0 0.921 0.086 1.303 0.258 0.383 0.172 0.705 0.405 0.969 0.709 0.265 0.301 0.467 0.652 0.605 1.06 0.143 0.403 0.213 0.843 0.213 1.313 0 0.461-0.07 0.892-0.213 1.288-0.141 0.397-0.343 0.746-0.605 1.041-0.264 0.296-0.586 0.526-0.969 0.694-0.382 0.168-0.814 0.253-1.303 0.253-0.481 0-0.913-0.085-1.298-0.253-0.384-0.168-0.708-0.398-0.973-0.694-0.263-0.295-0.466-0.644-0.606-1.041-0.141-0.396-0.211-0.827-0.211-1.288 0-0.47 0.07-0.91 0.211-1.313zm1.262 2.089c0.062 0.252 0.16 0.479 0.295 0.68 0.135 0.199 0.312 0.36 0.527 0.48 0.218 0.121 0.481 0.184 0.792 0.184 0.312 0 0.576-0.062 0.792-0.184 0.219-0.12 0.395-0.281 0.529-0.48 0.134-0.201 0.232-0.428 0.295-0.68 0.062-0.25 0.092-0.509 0.092-0.773 0-0.276-0.029-0.547-0.092-0.807-0.062-0.261-0.161-0.49-0.295-0.695-0.137-0.203-0.312-0.365-0.529-0.486-0.216-0.12-0.48-0.182-0.792-0.182-0.311 0-0.574 0.062-0.792 0.182-0.216 0.121-0.393 0.283-0.527 0.486-0.135 0.205-0.233 0.437-0.295 0.695s-0.093 0.527-0.093 0.807c0.001 0.264 0.032 0.523 0.093 0.773z"
|
||||
/><path
|
||||
id="path33-4-9-1"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m50.092 17.415 1.47 4.35h0.021l1.391-4.35h1.944v6.324h-1.294v-4.482h-0.019l-1.541 4.482h-1.062l-1.54-4.438h-0.019v4.438h-1.295v-6.324h1.944z"
|
||||
/><path
|
||||
id="path35-8-7-3"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m59.765 17.415 2.35 6.324h-1.436l-0.475-1.408h-2.35l-0.494 1.408h-1.392l2.377-6.324h1.42zm0.079 3.88-0.793-2.321h-0.019l-0.816 2.321h1.628z"
|
||||
/><path
|
||||
id="path37-6-1-3"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m64.547 17.415v6.324h-1.382v-6.324h1.382z"
|
||||
/><path
|
||||
id="path39-3-0-1"
|
||||
style="fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m67.603 17.415 2.623 4.242h0.018v-4.242h1.295v6.324h-1.383l-2.613-4.234h-0.018v4.234h-1.295v-6.324h1.373z"
|
||||
/></g
|
||||
><path
|
||||
id="path3912-1-5"
|
||||
d="m336.08-360.91c-51.67 0-93.562 40.444-93.562 90.336 0 49.885 41.892 90.336 93.57 90.336 51.67 0 93.562-40.452 93.562-90.336-0.008-49.893-41.9-90.336-93.57-90.336z"
|
||||
style="stroke:#000000;stroke-width:10.267;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
/><path
|
||||
id="path27-9-4-1-6"
|
||||
d="m359.71-299.7c-1.4695-2.3655-3.2974-4.4444-5.5016-6.2543-2.2401-1.81-4.7489-3.2077-7.5445-4.2113-2.7418-1.0215-5.645-1.5232-8.7273-1.5232-5.5912 0-10.286 1.111-14.175 3.2794-3.8887 2.1505-7.0965 5.0715-9.444 8.7094-2.4552 3.6558-4.1576 7.8133-5.3045 12.455-1.1111 4.6593-1.6666 9.4799-1.6666 14.444 0 4.7848 0.55549 9.4082 1.6666 13.906 1.1111 4.498 2.8494 8.5481 5.3045 12.132 2.4013 3.602 5.5732 6.4693 9.444 8.6556 3.8888 2.1505 8.5839 3.2436 14.175 3.2436 7.5983 0 13.512-2.3117 17.741-6.9711 4.2293-4.6593 6.8635-10.788 7.8313-18.422h23.96c-0.60926 7.0965-2.258 13.494-4.8564 19.211-2.6164 5.6987-6.093 10.591-10.394 14.605-4.3009 4.0142-9.3366 7.0786-15.161 9.1933-5.7704 2.1325-12.15 3.1898-19.067 3.1898-8.6019 0-16.379-1.5053-23.279-4.5159-6.8635-3.0465-12.706-7.1503-17.419-12.473-4.749-5.2866-8.3868-11.487-10.86-18.637-2.5626-7.1503-3.817-14.856-3.817-23.117 0-8.4585 1.2544-16.308 3.817-23.547 2.5268-7.2399 6.1647-13.566 10.86-18.96 4.7131-5.412 10.555-9.6233 17.419-12.706 6.8994-3.0823 14.623-4.6235 23.279-4.6235 6.2184 0 12.096 0.91395 17.562 2.6881 5.5374 1.8279 10.448 4.4443 14.82 7.8671 4.3547 3.4228 7.9568 7.7058 10.806 12.777 2.8672 5.0715 4.6235 10.896 5.394 17.455h-23.996c-0.42988-2.8493-1.3978-5.4658-2.8673-7.8492z"
|
||||
style="fill:#000000"
|
||||
inkscape:connector-curvature="0"
|
||||
/><path
|
||||
id="path4039-5-1"
|
||||
d="m250.51-308.07 174.92 51.631"
|
||||
style="stroke-linejoin:round;stroke:#000000;stroke-linecap:round;stroke-width:10.267;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
/></g
|
||||
><metadata
|
||||
><rdf:RDF
|
||||
><cc:Work
|
||||
><dc:format
|
||||
>image/svg+xml</dc:format
|
||||
><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
|
||||
/><cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/publicdomain/"
|
||||
/><dc:publisher
|
||||
><cc:Agent
|
||||
rdf:about="http://openclipart.org/"
|
||||
><dc:title
|
||||
>Openclipart</dc:title
|
||||
></cc:Agent
|
||||
></dc:publisher
|
||||
></cc:Work
|
||||
><cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/publicdomain/"
|
||||
><cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction"
|
||||
/><cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution"
|
||||
/><cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks"
|
||||
/></cc:License
|
||||
></rdf:RDF
|
||||
></metadata
|
||||
></svg
|
||||
>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
// This code is adapted from a sample found at the URL
|
||||
// "http://blogs.msdn.com/b/jmanning/archive/2004/12/19/325699.aspx"
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace TcpEchoServer
|
||||
{
|
||||
public class TcpEchoServer
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
Console.WriteLine("Starting echo server...");
|
||||
|
||||
int port = 9100;
|
||||
TcpListener listener = new TcpListener(IPAddress.Loopback, port);
|
||||
listener.Start();
|
||||
|
||||
TcpClient client = listener.AcceptTcpClient();
|
||||
NetworkStream stream = client.GetStream();
|
||||
StreamWriter writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true };
|
||||
StreamReader reader = new StreamReader(stream, Encoding.ASCII);
|
||||
|
||||
while (true)
|
||||
{
|
||||
string inputLine = "";
|
||||
while (inputLine != null)
|
||||
{
|
||||
inputLine = reader.ReadLine();
|
||||
writer.Write("E");
|
||||
Console.WriteLine("Echoing string: " + inputLine);
|
||||
}
|
||||
Console.WriteLine("Server saw disconnect from client.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ESCPOS_NET\ESCPOS_NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,77 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using Xunit;
|
||||
|
||||
namespace ESCPOS_NET.UnitTest.EmittersBased.EPSONTests
|
||||
{
|
||||
public class BarCode
|
||||
{
|
||||
private const string WEBSITE_STRING = "https://github.com/lukevp/ESC-POS-.NET/";
|
||||
|
||||
[Theory]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL1, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_15)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_25)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_30)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.EXTRA, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.LARGE, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.NORMAL, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.SMALL, CorrectionLevel2DCode.PERCENT_7)]
|
||||
[InlineData(TwoDimensionCodeType.QRCODE_MICRO, Size2DCode.TINY, CorrectionLevel2DCode.PERCENT_7)]
|
||||
public void PrintQRCode_Success(TwoDimensionCodeType codeType, Size2DCode size2DCode, CorrectionLevel2DCode correctionLevel2DCode)
|
||||
{
|
||||
var result = new byte[] { 29, 40, 107, 4, 0, 49, 65, (byte)codeType, 0, 29, 40, 107, 3, 0, 49, 67, (byte)size2DCode, 29, 40, 107, 3, 0, 49, 69, (byte)correctionLevel2DCode, 29, 40, 107, 42, 0, 49, 80, 48, 104, 116, 116, 112, 115, 58, 47, 47, 103, 105, 116, 104, 117, 98, 46, 99, 111, 109, 47, 108, 117, 107, 101, 118, 112, 47, 69, 83, 67, 45, 80, 79, 83, 45, 46, 78, 69, 84, 47, 29, 40, 107, 3, 0, 49, 81, 48 };
|
||||
Assert.Equal(result, new EPSON().Print2DCode(codeType, WEBSITE_STRING, size2DCode, correctionLevel2DCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Xunit;
|
||||
|
||||
namespace ESCPOS_NET.UnitTest.GlobalTests
|
||||
{
|
||||
public class Barcode
|
||||
{
|
||||
private const string WEBSITE_STRING = "https://github.com/lukevp/ESC-POS-.NET/";
|
||||
|
||||
[Theory]
|
||||
[InlineData("EPSON", TwoDimensionCodeType.QRCODE_MODEL1)]
|
||||
[InlineData("EPSON", TwoDimensionCodeType.QRCODE_MODEL2)]
|
||||
[InlineData("EPSON", TwoDimensionCodeType.QRCODE_MICRO)]
|
||||
[InlineData("EPSON", null)]
|
||||
public void PrintQRCode_Success(string emitter, TwoDimensionCodeType? codeType)
|
||||
{
|
||||
var type = Assembly.LoadFrom("ESCPOS_NET").GetType($"ESCPOS_NET.Emitters.{emitter}", true);
|
||||
ICommandEmitter e = (ICommandEmitter)Activator.CreateInstance(type);
|
||||
|
||||
byte[] bytes;
|
||||
if (codeType is TwoDimensionCodeType codeTypeValue)
|
||||
bytes = e.PrintQRCode(WEBSITE_STRING, codeTypeValue);
|
||||
else
|
||||
bytes = e.PrintQRCode(WEBSITE_STRING);
|
||||
|
||||
Assert.True(bytes.Length > 0);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("EPSON", TwoDimensionCodeType.PDF417)]
|
||||
public void PrintQRCode_Failure(string emitter, TwoDimensionCodeType codeType)
|
||||
{
|
||||
var type = Assembly.LoadFrom("ESCPOS_NET").GetType($"ESCPOS_NET.Emitters.{emitter}", true);
|
||||
ICommandEmitter e = (ICommandEmitter)Activator.CreateInstance(type);
|
||||
Assert.Throws<ArgumentException>(() => e.PrintQRCode(WEBSITE_STRING, codeType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31515.178
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ESCPOS_NET", "ESCPOS_NET\ESCPOS_NET.csproj", "{BA181101-43A5-435E-8744-ACDA313D04D8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ESCPOS_NET.ConsoleTest", "ESCPOS_NET.ConsoleTest\ESCPOS_NET.ConsoleTest.csproj", "{958464FE-6B30-4BA7-A4B1-D63ED2E23158}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ESCPOS_NET.UnitTest", "ESCPOS_NET.UnitTest\ESCPOS_NET.UnitTest.csproj", "{8A848879-9776-4EBC-8484-41B8EE65FD8D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BA181101-43A5-435E-8744-ACDA313D04D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BA181101-43A5-435E-8744-ACDA313D04D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BA181101-43A5-435E-8744-ACDA313D04D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BA181101-43A5-435E-8744-ACDA313D04D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{958464FE-6B30-4BA7-A4B1-D63ED2E23158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{958464FE-6B30-4BA7-A4B1-D63ED2E23158}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{958464FE-6B30-4BA7-A4B1-D63ED2E23158}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{958464FE-6B30-4BA7-A4B1-D63ED2E23158}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8A848879-9776-4EBC-8484-41B8EE65FD8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8A848879-9776-4EBC-8484-41B8EE65FD8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8A848879-9776-4EBC-8484-41B8EE65FD8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8A848879-9776-4EBC-8484-41B8EE65FD8D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FB679B5F-BE89-407A-820F-185FE53B15C5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
/* FROM: https://www.codeproject.com/Tips/674256/ByteArrayBuilder-a-StringBuilder-for-Bytes 2/9/2019 */
|
||||
namespace ESCPOS_NET.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides similar functionality to a StringBuilder, but for bytes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To fill the builder, construct a new, empty builder, and call the
|
||||
/// appropriate Append method overloads.
|
||||
/// To read data from the builder, either use Rewind on an existing
|
||||
/// builder, or construct a new builder by passing it the byte array
|
||||
/// from a previous builder - which you can get with the ToArray
|
||||
/// method.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
///
|
||||
/// ByteArrayBuilder bab = new ByteArrayBuilder();
|
||||
/// string[] lines = File.ReadAllLines(@"D:\Temp\myText.txt");
|
||||
/// bab.Append(lines.Length);
|
||||
/// foreach (string s in lines)
|
||||
/// {
|
||||
/// bab.Append(s);
|
||||
/// }
|
||||
/// byte[] data = bab.ToArray();
|
||||
/// ...
|
||||
/// ByteArrayBuilder babOut = new ByteArrayBuilder(data);
|
||||
/// int count = bab.GetInt();
|
||||
/// string[] linesOut = new string[count];
|
||||
/// for (int lineNo = 0; lineNo < count; lineNo++)
|
||||
/// {
|
||||
/// linesOut[lineNo](babOut.GetString());
|
||||
/// }
|
||||
/// .
|
||||
/// </example>
|
||||
public class ByteArrayBuilder : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// True in a byte form of the Line.
|
||||
/// </summary>
|
||||
private const byte StreamTrue = (byte)1;
|
||||
|
||||
/// <summary>
|
||||
/// False in the byte form of a line.
|
||||
/// </summary>
|
||||
private const byte StreamFalse = (byte)0;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the actual bytes.
|
||||
/// </summary>
|
||||
private MemoryStream store = new MemoryStream();
|
||||
|
||||
/// <summary>
|
||||
/// Gets bytes in the store.
|
||||
/// </summary>
|
||||
public int Length => (int)store.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty builder ready to be filled.
|
||||
/// </summary>
|
||||
public ByteArrayBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
public ByteArrayBuilder Append(byte b)
|
||||
{
|
||||
AddBytes(new byte[] { b });
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an IEnumerable of bytes to an array.
|
||||
/// </summary>
|
||||
/// <param name="b">Value to append to existing builder data.</param>
|
||||
/// </param>
|
||||
public ByteArrayBuilder Append(IEnumerable<byte> b)
|
||||
{
|
||||
if (b is byte[])
|
||||
{
|
||||
AddBytes((byte[])b);
|
||||
return this;
|
||||
}
|
||||
|
||||
AddBytes(b.ToArray());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all content from the builder.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
store.Close();
|
||||
store.Dispose();
|
||||
store = new MemoryStream();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rewind the builder ready to read data.
|
||||
/// </summary>
|
||||
public void Rewind()
|
||||
{
|
||||
store.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set an absolute position in the builder.
|
||||
/// **WARNING**
|
||||
/// If you add any variable size objects to the builder, the results of
|
||||
/// reading after a Seek to a non-zero value are unpredictable.
|
||||
/// A builder does not store just objects - for some it stores additional
|
||||
/// information as well.
|
||||
/// </summary>
|
||||
/// <param name="position">the position to seek.</param>
|
||||
public void Seek(int position)
|
||||
{
|
||||
store.Seek((long)position, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the builder as an array of bytes.
|
||||
/// </summary>
|
||||
/// <returns>An array.</returns>
|
||||
public byte[] ToArray()
|
||||
{
|
||||
byte[] data = new byte[Length];
|
||||
Array.Copy(store.GetBuffer(), data, Length);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a text based (Base64) string version of the current content.
|
||||
/// </summary>
|
||||
/// <returns>The converted string.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return Convert.ToBase64String(ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a string of raw bytes to the store.
|
||||
/// </summary>
|
||||
/// <param name="byteArray">the byte array.</param>
|
||||
private void AddBytes(byte[] byteArray)
|
||||
{
|
||||
store.Write(byteArray, 0, byteArray.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a specific number of bytes from the store.
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array.</returns>
|
||||
private byte[] GetBytes(int length)
|
||||
{
|
||||
byte[] data = new byte[length];
|
||||
if (length > 0)
|
||||
{
|
||||
int read = store.Read(data, 0, length);
|
||||
if (read != length)
|
||||
{
|
||||
throw new ApplicationException("Buffer did not contain " + length + " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of this builder and its resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
store.Close();
|
||||
store.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace ESCPOS_NET
|
||||
{
|
||||
public static class ByteExtensions
|
||||
{
|
||||
public static bool IsBitSet(this byte b, int offset)
|
||||
{
|
||||
return (b & (1 << offset)) != 0;
|
||||
}
|
||||
|
||||
public static bool IsBitNotSet(this byte b, int offset)
|
||||
{
|
||||
return (b & (1 << offset)) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace ESCPOS_NET.Utilities
|
||||
{
|
||||
public static class ByteSplicer
|
||||
{
|
||||
public static byte[] Combine(params byte[][] byteArrays)
|
||||
{
|
||||
ByteArrayBuilder builder = new ByteArrayBuilder();
|
||||
foreach (var byteArray in byteArrays)
|
||||
{
|
||||
builder.Append(byteArray);
|
||||
}
|
||||
return builder.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ESCPOS_NET.DataValidation
|
||||
{
|
||||
public class DataConstraint
|
||||
{
|
||||
public int MinLength { get; set; }
|
||||
|
||||
public int MaxLength { get; set; }
|
||||
|
||||
public List<int> ValidLengths { get; set; }
|
||||
|
||||
public string ValidChars { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using ESCPOS_NET.Emitters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ESCPOS_NET.DataValidation
|
||||
{
|
||||
public abstract class BaseDataValidator<T> where T : Enum
|
||||
{
|
||||
protected Dictionary<T, DataConstraint> _constraints;
|
||||
|
||||
public void Validate(T type, string data, BarcodeCode? code = null)
|
||||
{
|
||||
if (data is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
// Validate constraints on barcode.
|
||||
_constraints.TryGetValue(type, out var constraints);
|
||||
if (constraints is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check lengths
|
||||
if (constraints.ValidLengths != null)
|
||||
{
|
||||
if (!constraints.ValidLengths.Contains(data.Length))
|
||||
{
|
||||
throw new ArgumentException($"Code '{data}' is not a valid length from: [{string.Join(", ", constraints.ValidLengths)}].");
|
||||
}
|
||||
}
|
||||
else if (data.Length < constraints.MinLength)
|
||||
{
|
||||
throw new ArgumentException($"Code '{data}' is shorter than minimum length {constraints.MinLength}.");
|
||||
}
|
||||
else if (data.Length > constraints.MaxLength)
|
||||
{
|
||||
throw new ArgumentException($"Code '{data}' is longer than maximum length {constraints.MaxLength}.");
|
||||
}
|
||||
|
||||
// Check if barcode contains invalid characters.
|
||||
if (constraints.ValidChars == "7BIT-ASCII")
|
||||
{
|
||||
if (!data.All(x => x <= 127 && x >= 0))
|
||||
{
|
||||
throw new ArgumentException($"Code '{data}' contained invalid characters not in: {constraints.ValidChars}.");
|
||||
}
|
||||
}
|
||||
else if (constraints.ValidChars != null && !data.All(x => constraints.ValidChars.Contains(x)))
|
||||
{
|
||||
throw new ArgumentException($"Code '{data}' contained invalid characters not in: {constraints.ValidChars}.");
|
||||
}
|
||||
|
||||
RunSpecificValidations(type, data, code);
|
||||
}
|
||||
|
||||
protected abstract void RunSpecificValidations(T type, string data, BarcodeCode? code);
|
||||
}
|
||||
|
||||
public static class DataValidator
|
||||
{
|
||||
private static BarcodeDataValidator singletonBarcode = null;
|
||||
private static TwoDimensionCodeDataValidator singleton2DCode = null;
|
||||
|
||||
public static void ValidateBarcode(BarcodeType type, BarcodeCode code, string data)
|
||||
{
|
||||
if (singletonBarcode is null)
|
||||
{
|
||||
singletonBarcode = new BarcodeDataValidator();
|
||||
}
|
||||
|
||||
singletonBarcode.Validate(type, data, code);
|
||||
}
|
||||
|
||||
public static void Validate2DCode(TwoDimensionCodeType type, string data)
|
||||
{
|
||||
if (singleton2DCode is null)
|
||||
{
|
||||
singleton2DCode = new TwoDimensionCodeDataValidator();
|
||||
}
|
||||
|
||||
singleton2DCode.Validate(type, data);
|
||||
}
|
||||
|
||||
private class BarcodeDataValidator : BaseDataValidator<BarcodeType>
|
||||
{
|
||||
public BarcodeDataValidator()
|
||||
{
|
||||
_constraints = new Dictionary<BarcodeType, DataConstraint>()
|
||||
{
|
||||
{ BarcodeType.UPC_A, new DataConstraint() { MinLength = 11, MaxLength = 12, ValidChars = "0123456789" } },
|
||||
{ BarcodeType.UPC_E, new DataConstraint() { ValidLengths = new List<int>() { 6, 7, 8, 11, 12 }, ValidChars = "0123456789" } },
|
||||
{ BarcodeType.JAN13_EAN13, new DataConstraint() { MinLength = 12, MaxLength = 13, ValidChars = "0123456789" } },
|
||||
{ BarcodeType.JAN8_EAN8, new DataConstraint() { MinLength = 7, MaxLength = 8, ValidChars = "0123456789" } },
|
||||
{ BarcodeType.CODE39, new DataConstraint() { MinLength = 1, MaxLength = 255, ValidChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./" } },
|
||||
{ BarcodeType.ITF, new DataConstraint() { MinLength = 2, MaxLength = 255, ValidChars = "0123456789" } },
|
||||
{ BarcodeType.CODABAR_NW_7, new DataConstraint() { MinLength = 2, MaxLength = 255, ValidChars = "0123456789ABCDabcd$+-./:" } },
|
||||
{ BarcodeType.CODE93, new DataConstraint() { MinLength = 1, MaxLength = 255, ValidChars = "7BIT-ASCII" } },
|
||||
{ BarcodeType.CODE128, new DataConstraint() { MinLength = 1, MaxLength = 253, ValidChars = "7BIT-ASCII" } },
|
||||
{ BarcodeType.GS1_128, new DataConstraint() { MinLength = 1, MaxLength = 253, ValidChars = "7BIT-ASCII" } },
|
||||
{ BarcodeType.GS1_DATABAR_OMNIDIRECTIONAL, new DataConstraint() { MinLength = 13, MaxLength = 13, ValidChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./" } },
|
||||
{ BarcodeType.GS1_DATABAR_TRUNCATED, new DataConstraint() { MinLength = 13, MaxLength = 13, ValidChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./" } },
|
||||
{ BarcodeType.GS1_DATABAR_LIMITED, new DataConstraint() { MinLength = 13, MaxLength = 13, ValidChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./" } },
|
||||
{ BarcodeType.GS1_DATABAR_EXPANDED, new DataConstraint() { MinLength = 2, MaxLength = 255, ValidChars = "0123456789ABCDabcd !\"%$'()*+,-./:;<=>?_{" } },
|
||||
};
|
||||
}
|
||||
|
||||
protected override void RunSpecificValidations(BarcodeType type, string barcode, BarcodeCode? code)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BarcodeType.UPC_E:
|
||||
if (barcode.Length != 6 && !barcode.StartsWith("0", StringComparison.InvariantCulture))
|
||||
{
|
||||
throw new ArgumentException($"UPC_E Barcode {barcode} with length of 7, 8, 11, or 12 must start with 0.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BarcodeType.ITF:
|
||||
if (barcode.Length % 2 != 0)
|
||||
{
|
||||
throw new ArgumentException($"ITF Barcode {barcode} has length {barcode.Length}, which is not an even number.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BarcodeType.CODABAR_NW_7:
|
||||
if (!"ABCD".Contains(barcode[0]) || !"ABCD".Contains(barcode[barcode.Length - 1]))
|
||||
{
|
||||
throw new ArgumentException($"CODABAR_NW_7 Barcode {barcode} must start and end with an ABCD character.");
|
||||
}
|
||||
|
||||
if (barcode.Skip(1).Take(barcode.Length - 2).Any(x => "ABCD".Contains(x)))
|
||||
{
|
||||
throw new ArgumentException($"CODABAR_NW_7 Barcode {barcode} must not include ABCD characters in the body of the barcode.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BarcodeType.CODE93:
|
||||
if (!barcode.StartsWith("*", StringComparison.InvariantCulture) || !barcode.EndsWith("*", StringComparison.InvariantCulture))
|
||||
{
|
||||
throw new ArgumentException($"CODE93 Barcode {barcode} must start and end with * characters.");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BarcodeType.CODE128:
|
||||
if (code == BarcodeCode.CODE_C)
|
||||
{
|
||||
if (barcode.Length % 2 != 0)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(barcode)} length must be divisible by 2");
|
||||
}
|
||||
|
||||
if (!barcode.All(x => x <= '9' && x >= '0'))
|
||||
{
|
||||
throw new ArgumentException($"Barcode {barcode} is invalid. CODE128 CODE_C barcodes only support numeric characters.");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TwoDimensionCodeDataValidator : BaseDataValidator<TwoDimensionCodeType>
|
||||
{
|
||||
public TwoDimensionCodeDataValidator()
|
||||
{
|
||||
_constraints = new Dictionary<TwoDimensionCodeType, DataConstraint>()
|
||||
{
|
||||
{ TwoDimensionCodeType.PDF417, new DataConstraint() { MinLength = 0, MaxLength = 255 } },
|
||||
{ TwoDimensionCodeType.QRCODE_MODEL1, new DataConstraint() { MinLength = 0, MaxLength = 707 } },
|
||||
{ TwoDimensionCodeType.QRCODE_MODEL2, new DataConstraint() { MinLength = 0, MaxLength = 4296 } },
|
||||
{ TwoDimensionCodeType.QRCODE_MICRO, new DataConstraint() { MinLength = 0, MaxLength = 21 } },
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Research specific validations for QRCode & PDF417
|
||||
protected override void RunSpecificValidations(TwoDimensionCodeType type, string barcode, BarcodeCode? code)
|
||||
{
|
||||
if (code != null)
|
||||
{
|
||||
throw new ArgumentException($"Barcode code should be always null for 2D Codes.", nameof(code));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Company>animalistic.io</Company>
|
||||
<Product>ESCPOS_NET</Product>
|
||||
<Authors>Luke Paireepinart</Authors>
|
||||
<Description>.NET Standard 2.0 Implementation of ESC/POS command generation and integration with thermal printers.
|
||||
Allows creating receipts with all common functionality supported.</Description>
|
||||
<Copyright>Copyright 2021 CandL Development, LLC.</Copyright>
|
||||
<PackageLicenseUrl></PackageLicenseUrl>
|
||||
<RepositoryUrl>https://github.com/lukevp/ESC-POS-.NET</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>epson thermal receipt printing printer usb wifi bluetooth serial esc pos escpos escp esc/pos esc/pos.net esc_pos esc_pos_net esc_pos_usb esc_pos_usb_net</PackageTags>
|
||||
<Version>2.0.0</Version>
|
||||
<AssemblyVersion>2.0.0.0</AssemblyVersion>
|
||||
<FileVersion>2.0.0.0</FileVersion>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://github.com/lukevp/ESC-POS-.NET</PackageProjectUrl>
|
||||
<PackageReleaseNotes>- Completely rebuilt the network printer code</PackageReleaseNotes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0" />
|
||||
<PackageReference Include="SuperSimpleTcp" Version="2.4.0" />
|
||||
<PackageReference Include="System.IO.Ports" Version="4.6.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,16 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Action Commands */
|
||||
public virtual byte[] FullCut() => new byte[] { Cmd.GS, Ops.PaperCut, Functions.PaperCutFullCut };
|
||||
|
||||
public virtual byte[] PartialCut() => new byte[] { Cmd.GS, Ops.PaperCut, Functions.PaperCutPartialCut };
|
||||
|
||||
public virtual byte[] FullCutAfterFeed(int lineCount) => new byte[] { Cmd.GS, Ops.PaperCut, Functions.PaperCutFullCutWithFeed, (byte)lineCount };
|
||||
|
||||
public virtual byte[] PartialCutAfterFeed(int lineCount) => new byte[] { Cmd.GS, Ops.PaperCut, Functions.PaperCutPartialCutWithFeed, (byte)lineCount };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using ESCPOS_NET.DataValidation;
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
using ESCPOS_NET.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Barcode Commands */
|
||||
public virtual byte[] PrintBarcode(BarcodeType type, string barcode, BarcodeCode code = BarcodeCode.CODE_B)
|
||||
{
|
||||
DataValidator.ValidateBarcode(type, code, barcode);
|
||||
return BarcodeBytes(type, barcode, code);
|
||||
}
|
||||
|
||||
protected virtual byte[] BarcodeBytes(BarcodeType type, string barcode, BarcodeCode code)
|
||||
{
|
||||
// For CODE128, prepend the first 2 characters as 0x7B and the CODE type, and escape 0x7B characters.
|
||||
if (type == BarcodeType.CODE128)
|
||||
{
|
||||
if (code == BarcodeCode.CODE_C)
|
||||
{
|
||||
byte[] b = Encoding.ASCII.GetBytes(barcode);
|
||||
byte[] ob = new byte[b.Length / 2];
|
||||
for (int i = 0, obc = 0; i < b.Length; i += 2)
|
||||
{
|
||||
ob[obc++] = (byte)(((b[i] - '0') * 10) + (b[i + 1] - '0'));
|
||||
}
|
||||
|
||||
barcode = Encoding.ASCII.GetString(ob);
|
||||
}
|
||||
|
||||
barcode = barcode.Replace("{", "{{");
|
||||
barcode = $"{(char)0x7B}{(char)code}" + barcode;
|
||||
}
|
||||
|
||||
var command = new List<byte> { Cmd.GS, Barcodes.PrintBarcode, (byte)type, (byte)barcode.Length };
|
||||
command.AddRange(barcode.ToCharArray().Select(x => (byte)x));
|
||||
return command.ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] PrintQRCode(string data, TwoDimensionCodeType type = TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode size = Size2DCode.NORMAL, CorrectionLevel2DCode correction = CorrectionLevel2DCode.PERCENT_7)
|
||||
{
|
||||
if (type == TwoDimensionCodeType.PDF417)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(TwoDimensionCodeType.PDF417)} is not a valid QRCode type. Please use {nameof(Print2DCode)} method", nameof(type));
|
||||
}
|
||||
|
||||
return Print2DCode(type, data, size, correction);
|
||||
}
|
||||
|
||||
public virtual byte[] Print2DCode(TwoDimensionCodeType type, string data, Size2DCode size = Size2DCode.NORMAL, CorrectionLevel2DCode correction = CorrectionLevel2DCode.PERCENT_7)
|
||||
{
|
||||
DataValidator.Validate2DCode(type, data);
|
||||
return TwoDimensionCodeBytes(type, data, size, correction);
|
||||
}
|
||||
|
||||
protected virtual byte[] TwoDimensionCodeBytes(TwoDimensionCodeType type, string data, Size2DCode size, CorrectionLevel2DCode correction)
|
||||
{
|
||||
List<byte> command = new List<byte>();
|
||||
byte[] initial = { Cmd.GS, Barcodes.Set2DCode, Barcodes.PrintBarcode };
|
||||
switch (type)
|
||||
{
|
||||
case TwoDimensionCodeType.PDF417:
|
||||
command.AddRange(initial, Barcodes.SetPDF417NumberOfColumns, Barcodes.AutoEnding);
|
||||
command.AddRange(initial, Barcodes.SetPDF417NumberOfRows, Barcodes.AutoEnding);
|
||||
command.AddRange(initial, Barcodes.SetPDF417DotSize, (byte)size);
|
||||
command.AddRange(initial, Barcodes.SetPDF417CorrectionLevel, (byte)correction);
|
||||
|
||||
// k = (pL + pH * 256) - 3 --> But pH is always 0.
|
||||
int k = data.Length;
|
||||
int l = k + 3;
|
||||
command.AddRange(initial, (byte)l, Barcodes.StorePDF417Data);
|
||||
command.AddRange(data.ToCharArray().Select(x => (byte)x));
|
||||
|
||||
// Prints stored PDF417
|
||||
command.AddRange(initial, Barcodes.PrintPDF417);
|
||||
break;
|
||||
|
||||
case TwoDimensionCodeType.QRCODE_MODEL1:
|
||||
case TwoDimensionCodeType.QRCODE_MODEL2:
|
||||
case TwoDimensionCodeType.QRCODE_MICRO:
|
||||
command.AddRange(initial, Barcodes.SelectQRCodeModel, (byte)type, Barcodes.AutoEnding);
|
||||
command.AddRange(initial, Barcodes.SetQRCodeDotSize, (byte)size);
|
||||
command.AddRange(initial, Barcodes.SetQRCodeCorrectionLevel, (byte)correction);
|
||||
int num = data.Length + 3;
|
||||
int pL = num % 256;
|
||||
int pH = num / 256;
|
||||
command.AddRange(initial, (byte)pL, (byte)pH, Barcodes.StoreQRCodeData);
|
||||
command.AddRange(data.ToCharArray().Select(x => (byte)x));
|
||||
|
||||
// Prints stored QRCode
|
||||
command.AddRange(initial, Barcodes.PrintQRCode);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"2D Code '{type}' was not implemented yet.");
|
||||
}
|
||||
|
||||
return command.ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] SetBarcodeHeightInDots(int height) => new byte[] { Cmd.GS, Barcodes.SetBarcodeHeightInDots, (byte)height };
|
||||
|
||||
public virtual byte[] SetBarWidth(BarWidth width) => new byte[] { Cmd.GS, Barcodes.SetBarWidth, (byte)width };
|
||||
|
||||
public virtual byte[] SetBarLabelPosition(BarLabelPrintPosition position) => new byte[] { Cmd.GS, Barcodes.SetBarLabelPosition, (byte)position };
|
||||
|
||||
public virtual byte[] SetBarLabelFontB(bool fontB) => new byte[] { Cmd.GS, Barcodes.SetBarLabelFont, (byte)(fontB ? 1 : 0) };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Cash Drawer Commands */
|
||||
public virtual byte[] CashDrawerOpenPin2(int pulseOnTimeMs = 120, int pulseOffTimeMs = 240) {
|
||||
return new byte[] { Cmd.ESC, Ops.CashDrawerPulse, 0x00, (byte) (pulseOnTimeMs / 2), (byte) (pulseOffTimeMs / 2) };
|
||||
}
|
||||
|
||||
public virtual byte[] CashDrawerOpenPin5(int pulseOnTimeMs = 120, int pulseOffTimeMs = 240) {
|
||||
return new byte[] { Cmd.ESC, Ops.CashDrawerPulse, 0x01, (byte) (pulseOnTimeMs / 2), (byte) (pulseOffTimeMs / 2) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Character Commands */
|
||||
public virtual byte[] SetStyles(PrintStyle style) => new byte[] { Cmd.ESC, Chars.StyleMode, (byte)style };
|
||||
|
||||
public virtual byte[] LeftAlign() => new byte[] { Cmd.ESC, Chars.Alignment, (byte)Align.Left };
|
||||
|
||||
public virtual byte[] CenterAlign() => new byte[] { Cmd.ESC, Chars.Alignment, (byte)Align.Center };
|
||||
|
||||
public virtual byte[] RightAlign() => new byte[] { Cmd.ESC, Chars.Alignment, (byte)Align.Right };
|
||||
|
||||
public virtual byte[] RightCharacterSpacing(int spaceCount) => new byte[] { Cmd.ESC, Chars.RightCharacterSpacing, (byte)spaceCount };
|
||||
|
||||
public virtual byte[] CodePage(CodePage codePage) => new byte[] { Cmd.ESC, Chars.CodePage, (byte)codePage };
|
||||
|
||||
public virtual byte[] Color(Color color) => new byte[] { Cmd.ESC, Chars.Color, (byte)color };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Display Commands */
|
||||
public virtual byte[] Clear() => new byte[] { Display.CLR };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
private byte[] GetImageHeader(int commandLength)
|
||||
{
|
||||
byte[] lengths = new byte[4];
|
||||
int i = 0;
|
||||
while (commandLength > 0)
|
||||
{
|
||||
lengths[i] = (byte)(commandLength & 0xFF);
|
||||
commandLength >>= 8;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= 3)
|
||||
{
|
||||
return new byte[] { Cmd.GS, Images.ImageCmd8, Images.ImageCmdL, lengths[0], lengths[1], lengths[2], lengths[3] };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new byte[] { Cmd.GS, Images.ImageCmdParen, Images.ImageCmdL, lengths[0], lengths[1] };
|
||||
}
|
||||
}
|
||||
|
||||
/* Image Commands */
|
||||
public virtual byte[] SetImageDensity(bool isHiDPI)
|
||||
{
|
||||
ByteArrayBuilder builder = new ByteArrayBuilder();
|
||||
byte dpiSetting = isHiDPI ? (byte)0x33 : (byte)0x32; // TODO: is this right??
|
||||
byte[] baseCommand = new byte[] { 0x30, 0x31, dpiSetting, dpiSetting };
|
||||
builder.Append(GetImageHeader(baseCommand.Length));
|
||||
builder.Append(baseCommand);
|
||||
return builder.ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] BufferImage(byte[] image, int maxWidth = -1, bool isLegacy = false, int color = 1)
|
||||
{
|
||||
ByteArrayBuilder imageCommand = new ByteArrayBuilder();
|
||||
|
||||
byte colorByte;
|
||||
switch (color)
|
||||
{
|
||||
case 2:
|
||||
colorByte = 0x32;
|
||||
break;
|
||||
case 3:
|
||||
colorByte = 0x33;
|
||||
break;
|
||||
default:
|
||||
colorByte = 0x31;
|
||||
break;
|
||||
}
|
||||
|
||||
int width;
|
||||
int height;
|
||||
byte[] imageData;
|
||||
using (var img = Image.Load(image))
|
||||
{
|
||||
imageData = img.ToSingleBitPixelByteArray(maxWidth: maxWidth == -1 ? (int?)null : maxWidth);
|
||||
height = img.Height;
|
||||
width = img.Width;
|
||||
}
|
||||
|
||||
byte heightL = (byte)height;
|
||||
byte heightH = (byte)(height >> 8);
|
||||
|
||||
if (isLegacy)
|
||||
{
|
||||
var byteWidth = (width + 7 & -8) / 8;
|
||||
byte widthL = (byte)byteWidth;
|
||||
byte widthH = (byte)(byteWidth >> 8);
|
||||
imageCommand.Append(new byte[] { Cmd.GS, Images.ImageCmdLegacy, 0x30, 0x00, widthL, widthH, heightL, heightH });
|
||||
}
|
||||
else
|
||||
{
|
||||
byte widthL = (byte)width;
|
||||
byte widthH = (byte)(width >> 8);
|
||||
imageCommand.Append(new byte[] { 0x30, 0x70, 0x30, 0x01, 0x01, colorByte, widthL, widthH, heightL, heightH });
|
||||
}
|
||||
|
||||
imageCommand.Append(imageData);
|
||||
|
||||
// Load image to print buffer
|
||||
ByteArrayBuilder response = new ByteArrayBuilder();
|
||||
byte[] imageCommandBytes = imageCommand.ToArray();
|
||||
if (!isLegacy)
|
||||
{
|
||||
response.Append(GetImageHeader(imageCommandBytes.Length));
|
||||
}
|
||||
|
||||
response.Append(imageCommandBytes);
|
||||
return response.ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] WriteImageFromBuffer()
|
||||
{
|
||||
// Print image that's already buffered.
|
||||
ByteArrayBuilder response = new ByteArrayBuilder();
|
||||
byte[] printCommandBytes = new byte[] { 0x30, 0x32 };
|
||||
response.Append(GetImageHeader(printCommandBytes.Length));
|
||||
response.Append(printCommandBytes);
|
||||
return response.ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] PrintImage(byte[] image, bool isHiDPI, bool isLegacy = false, int maxWidth = -1, int color = 1)
|
||||
{
|
||||
if (isLegacy)
|
||||
{
|
||||
return ByteSplicer.Combine(BufferImage(image, maxWidth, isLegacy));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ByteSplicer.Combine(SetImageDensity(isHiDPI), BufferImage(image, maxWidth, isLegacy, color), WriteImageFromBuffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
public virtual byte[] ResetLineSpacing() => new byte[] { Cmd.ESC, Whitespace.ResetLineSpacing };
|
||||
|
||||
public virtual byte[] SetLineSpacingInDots(int dots) => new byte[] { Cmd.ESC, Whitespace.LineSpacingInDots, (byte)dots };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Operational Commands */
|
||||
public virtual byte[] Initialize() => new byte[] { Cmd.ESC, Ops.Initialize };
|
||||
|
||||
public virtual byte[] Enable() => new byte[] { Cmd.ESC, Ops.EnableDisable, 1 };
|
||||
|
||||
public virtual byte[] Disable() => new byte[] { Cmd.ESC, Ops.EnableDisable, 0 };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Linq;
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Printing Commands */
|
||||
public virtual byte[] Print(string data)
|
||||
{
|
||||
// Fix OSX or Windows-style newlines
|
||||
data = data.Replace("\r\n", "\n");
|
||||
data = data.Replace("\r", "\n");
|
||||
|
||||
// TODO: Sanitize...
|
||||
return data.ToCharArray().Select(x => (byte)x).ToArray();
|
||||
}
|
||||
|
||||
public virtual byte[] PrintLine(string line)
|
||||
{
|
||||
if (line == null)
|
||||
{
|
||||
return Print("\n");
|
||||
}
|
||||
|
||||
return Print(line.Replace("\r", string.Empty).Replace("\n", string.Empty) + "\n");
|
||||
}
|
||||
|
||||
public virtual byte[] FeedLines(int lineCount) => new byte[] { Cmd.ESC, Whitespace.FeedLines, (byte)lineCount };
|
||||
|
||||
public virtual byte[] FeedLinesReverse(int lineCount) => new byte[] { Cmd.ESC, Whitespace.FeedLinesReverse, (byte)lineCount };
|
||||
|
||||
public virtual byte[] FeedDots(int dotCount) => new byte[] { Cmd.ESC, Whitespace.FeedDots, (byte)dotCount };
|
||||
|
||||
public virtual byte[] ReverseMode(bool enable) => new byte[] { Cmd.GS, Chars.ReversePrintMode, enable ? (byte)0x01 : (byte)0x00 };
|
||||
|
||||
public virtual byte[] UpsideDownMode(bool enable) => new byte[] { Cmd.ESC, Chars.UpsideDownMode, enable ? (byte)0x01 : (byte)0x00 };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public abstract partial class BaseCommandEmitter : ICommandEmitter
|
||||
{
|
||||
/* Status Commands */
|
||||
public virtual byte[] EnableAutomaticStatusBack() => new byte[] { Cmd.GS, Status.AutomaticStatusBack, 0xFF };
|
||||
|
||||
public virtual byte[] EnableAutomaticInkStatusBack() => new byte[] { Cmd.GS, Status.AutomaticInkStatusBack, 0xFF };
|
||||
public virtual byte[] DisableAutomaticStatusBack() => new byte[] { Cmd.GS, Status.AutomaticStatusBack, 0x00 };
|
||||
|
||||
public virtual byte[] DisableAutomaticInkStatusBack() => new byte[] { Cmd.GS, Status.AutomaticInkStatusBack, 0x00 };
|
||||
public virtual byte[] RequestPaperStatus() => new byte[] { Cmd.GS, Status.RequestStatus, 0x31 };
|
||||
public virtual byte[] RequestDrawerStatus() => new byte[] { Cmd.GS, Status.RequestStatus, 0x32 };
|
||||
public virtual byte[] RequestInkStatus() => new byte[] { Cmd.GS, Status.RequestStatus, 0x34 };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Barcodes
|
||||
{
|
||||
public static readonly byte PrintBarcode = 0x6B;
|
||||
public static readonly byte SetBarcodeHeightInDots = 0x68;
|
||||
public static readonly byte SetBarWidth = 0x77;
|
||||
public static readonly byte SetBarLabelPosition = 0x48;
|
||||
public static readonly byte SetBarLabelFont = 0x66;
|
||||
|
||||
public static readonly byte Set2DCode = 0x28;
|
||||
public static readonly byte AutoEnding = 0x00;
|
||||
public static readonly byte[] SetPDF417NumberOfColumns = { 0x03, 0x00, 0x30, 0x41 };
|
||||
public static readonly byte[] SetPDF417NumberOfRows = { 0x03, 0x00, 0x30, 0x42 };
|
||||
public static readonly byte[] SetPDF417DotSize = { 0x03, 0x00, 0x30, 0x43 };
|
||||
public static readonly byte[] SetPDF417CorrectionLevel = { 0x04, 0x00, 0x30, 0x45, 0x30 };
|
||||
public static readonly byte[] StorePDF417Data = { 0x00, 0x30, 0x50, 0x30 };
|
||||
public static readonly byte[] PrintPDF417 = { 0x03, 0x00, 0x30, 0x51, 0x30 };
|
||||
|
||||
public static readonly byte[] SelectQRCodeModel = { 0x04, 0x00, 0x31, 0x41 };
|
||||
public static readonly byte[] SetQRCodeDotSize = { 0x03, 0x00, 0x31, 0x43 };
|
||||
public static readonly byte[] SetQRCodeCorrectionLevel = { 0x03, 0x00, 0x31, 0x45 };
|
||||
public static readonly byte[] StoreQRCodeData = { 0x31, 0x50, 0x30 };
|
||||
public static readonly byte[] PrintQRCode = { 0x03, 0x00, 0x31, 0x51, 0x30 };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Chars
|
||||
{
|
||||
public static readonly byte StyleMode = 0x21;
|
||||
public static readonly byte Alignment = 0x61;
|
||||
public static readonly byte ReversePrintMode = 0x42;
|
||||
public static readonly byte RightCharacterSpacing = 0x20;
|
||||
public static readonly byte UpsideDownMode = 0x7B;
|
||||
public static readonly byte CodePage = 0x74;
|
||||
public static readonly byte Color = 0x72;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Cmd
|
||||
{
|
||||
public static readonly byte ESC = 0x1B;
|
||||
public static readonly byte GS = 0x1D;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Display
|
||||
{
|
||||
public static readonly byte CLR = 0x0C;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Functions
|
||||
{
|
||||
public static readonly byte PaperCutFullCut = 0x00;
|
||||
public static readonly byte PaperCutFullCutWithFeed = 0x41;
|
||||
public static readonly byte PaperCutPartialCut = 0x01;
|
||||
public static readonly byte PaperCutPartialCutWithFeed = 0x42;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Images
|
||||
{
|
||||
public static readonly byte ImageCmdParen = 0x28;
|
||||
public static readonly byte ImageCmdLegacy = 0x76;
|
||||
public static readonly byte ImageCmd8 = 0x38;
|
||||
public static readonly byte ImageCmdL = 0x4C;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Ops
|
||||
{
|
||||
public static readonly byte Initialize = 0x40;
|
||||
public static readonly byte EnableDisable = 0x3D;
|
||||
public static readonly byte PaperCut = 0x56;
|
||||
public static readonly byte CashDrawerPulse = 0x70;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Status
|
||||
{
|
||||
public static readonly byte AutomaticStatusBack = 0x61;
|
||||
public static readonly byte AutomaticInkStatusBack = 0x6A;
|
||||
public static readonly byte RequestStatus = 0x72;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace ESCPOS_NET.Emitters.BaseCommandValues
|
||||
{
|
||||
public static class Whitespace
|
||||
{
|
||||
// TODO: tabs?
|
||||
public static readonly byte Linefeed = 0x0A;
|
||||
public static readonly byte FeedLines = 0x64;
|
||||
public static readonly byte FeedLinesReverse = 0x65;
|
||||
public static readonly byte FeedDots = 0x4A;
|
||||
public static readonly byte ResetLineSpacing = 0x32;
|
||||
public static readonly byte LineSpacingInDots = 0x33;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public class EPSON : BaseCommandEmitter
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum TwoDimensionCodeType
|
||||
{
|
||||
PDF417 = 0,
|
||||
QRCODE_MODEL1 = 49,
|
||||
QRCODE_MODEL2 = 50,
|
||||
QRCODE_MICRO = 51,
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum Size2DCode
|
||||
{
|
||||
TINY = 2,
|
||||
SMALL = 3,
|
||||
NORMAL = 4,
|
||||
LARGE = 5,
|
||||
EXTRA = 6,
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum CorrectionLevel2DCode
|
||||
{
|
||||
PERCENT_7 = 48,
|
||||
PERCENT_15 = 49,
|
||||
PERCENT_25 = 50,
|
||||
PERCENT_30 = 51,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum Align
|
||||
{
|
||||
Left = 0,
|
||||
Center = 1,
|
||||
Right = 2,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment..")]
|
||||
public enum BarLabelPrintPosition
|
||||
{
|
||||
None = 0,
|
||||
Above = 1,
|
||||
Below = 2,
|
||||
Both = 3,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum BarWidth
|
||||
{
|
||||
Thinnest = 2,
|
||||
Thin = 3,
|
||||
Default = 4,
|
||||
Thick = 5,
|
||||
Thickest = 6,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public enum BarcodeCode
|
||||
{
|
||||
CODE_A = 0x41,
|
||||
CODE_B = 0x42,
|
||||
CODE_C = 0x43,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum BarcodeType // All from Function B
|
||||
{
|
||||
UPC_A = 0x41,
|
||||
UPC_E = 0x42,
|
||||
JAN13_EAN13 = 0x43,
|
||||
JAN8_EAN8 = 0x44,
|
||||
CODE39 = 0x45,
|
||||
ITF = 0x46,
|
||||
CODABAR_NW_7 = 0x47,
|
||||
CODE93 = 0x48,
|
||||
CODE128 = 0x49,
|
||||
GS1_128 = 0x4A,
|
||||
GS1_DATABAR_OMNIDIRECTIONAL = 0x4B,
|
||||
GS1_DATABAR_TRUNCATED = 0x4C,
|
||||
GS1_DATABAR_LIMITED = 0x4D,
|
||||
GS1_DATABAR_EXPANDED = 0x4E,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
#pragma warning disable SA1602 // Enumeration items should be documented
|
||||
#pragma warning disable SA1600 // Elements should be documented
|
||||
public enum CodePage
|
||||
{
|
||||
PC437_USA_STANDARD_EUROPE_DEFAULT = 0,
|
||||
KATAKANA = 1,
|
||||
PC850_MULTILINGUAL = 2,
|
||||
PC860_PORTUGUESE = 3,
|
||||
PC863_CANADIAN_FRENCH = 4,
|
||||
PC865_NORDIC = 5,
|
||||
HIRAGANA = 6,
|
||||
ONE_PASS_KANJI = 7,
|
||||
ONE_PASS_KANJI2 = 8,
|
||||
PC851_GREEK = 11,
|
||||
PC853_TURKISH = 12,
|
||||
PC857_TURKISH = 13,
|
||||
PC737_GREEK = 14,
|
||||
ISO8859_7_GREEK = 15,
|
||||
WPC1252 = 16,
|
||||
PC866_CYRILLIC2 = 17,
|
||||
PC852_LATIN2 = 18,
|
||||
PC858_EURO = 19,
|
||||
KU42_THAI = 20,
|
||||
TIS11_THAI = 21,
|
||||
TIS13_THAI = 22,
|
||||
TIS14_THAI = 23,
|
||||
TIS16_THAI = 24,
|
||||
TIS17_THAI = 25,
|
||||
TIS18_THAI = 26,
|
||||
TCVN3_VIETNAMESE_L = 30,
|
||||
TCVN3_VIETNAMESE_U = 31,
|
||||
PC720_ARABIC = 32,
|
||||
WPC775_BALTIC_RIM = 33,
|
||||
PC855_CYRILLIC = 34,
|
||||
PC861_ICELANDIC = 35,
|
||||
PC862_HEBREW = 36,
|
||||
PC864_ARABIC = 37,
|
||||
PC869_GREEK = 38,
|
||||
ISO8859_2_LATIN2 = 39,
|
||||
ISO8859_15_LATIN9 = 40,
|
||||
PC1098_FARSI = 41,
|
||||
PC1118_LITHUANIAN = 42,
|
||||
PC1119_LITHUANIAN = 43,
|
||||
PC1125_UKRANIAN = 44,
|
||||
WPC1250_LATIN2 = 45,
|
||||
WPC1251_CYRILLIC = 46,
|
||||
WPC1253_GREEK = 47,
|
||||
WPC1254_TURKISH = 48,
|
||||
WPC1255_HEBREW = 49,
|
||||
WPC1256_ARABIC = 50,
|
||||
WPC1257_BALTIC_RIM = 51,
|
||||
WPC1258_VIETNAMESE = 52,
|
||||
KZ1048_KAZAKHSTAN = 53,
|
||||
DEVANAGARI = 66,
|
||||
BENGALI = 67,
|
||||
TAMIL = 68,
|
||||
TELUGU = 69,
|
||||
ASSAMESE = 70,
|
||||
ORIYA = 71,
|
||||
KANNADA = 72,
|
||||
MALAYALAM = 73,
|
||||
GUJARATI = 74,
|
||||
PUNJABI = 75,
|
||||
MARATHI = 82,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum Color
|
||||
{
|
||||
Black = 0,
|
||||
Red = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "Enums are easier to read if they have whitespace alignment.")]
|
||||
public enum PrintStyle
|
||||
{
|
||||
None = 0,
|
||||
FontB = 1,
|
||||
Bold = 1 << 3,
|
||||
DoubleHeight = 1 << 4,
|
||||
DoubleWidth = 1 << 5,
|
||||
Underline = 1 << 7,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
namespace ESCPOS_NET.Emitters
|
||||
{
|
||||
public interface ICommandEmitter
|
||||
{
|
||||
/* Print Commands */
|
||||
byte[] PrintLine(string line = null);
|
||||
|
||||
byte[] Print(string line);
|
||||
|
||||
byte[] FeedLines(int lineCount);
|
||||
|
||||
byte[] FeedLinesReverse(int lineCount);
|
||||
|
||||
byte[] FeedDots(int dotCount);
|
||||
|
||||
/* Line Spacing Commands */
|
||||
byte[] ResetLineSpacing();
|
||||
|
||||
byte[] SetLineSpacingInDots(int dots);
|
||||
|
||||
/* Operational Commands */
|
||||
byte[] Initialize();
|
||||
|
||||
byte[] Enable();
|
||||
|
||||
byte[] Disable();
|
||||
|
||||
/* Cash Drawer Commands */
|
||||
byte[] CashDrawerOpenPin2(int pulseOnTimeMs = 120, int pulseOffTimeMs = 240);
|
||||
|
||||
byte[] CashDrawerOpenPin5(int pulseOnTimeMs = 120, int pulseOffTimeMs = 240);
|
||||
|
||||
/* Character Commands */
|
||||
byte[] SetStyles(PrintStyle style);
|
||||
|
||||
byte[] LeftAlign();
|
||||
|
||||
byte[] RightAlign();
|
||||
|
||||
byte[] CenterAlign();
|
||||
|
||||
byte[] ReverseMode(bool activate);
|
||||
|
||||
byte[] RightCharacterSpacing(int spaceCount);
|
||||
|
||||
byte[] UpsideDownMode(bool activate);
|
||||
|
||||
byte[] CodePage(CodePage codePage);
|
||||
|
||||
byte[] Color(Color color);
|
||||
|
||||
/* Action Commands */
|
||||
byte[] FullCut();
|
||||
|
||||
byte[] PartialCut();
|
||||
|
||||
byte[] FullCutAfterFeed(int lineCount);
|
||||
|
||||
byte[] PartialCutAfterFeed(int lineCount);
|
||||
|
||||
/* Image Commands */
|
||||
byte[] SetImageDensity(bool isHiDPI);
|
||||
|
||||
byte[] BufferImage(byte[] image, int maxWidth, bool isLegacy = false, int color = 1);
|
||||
|
||||
byte[] WriteImageFromBuffer();
|
||||
|
||||
byte[] PrintImage(byte[] image, bool isHiDPI, bool isLegacy = false, int maxWidth = -1, int color = 1);
|
||||
|
||||
/* Status Commands */
|
||||
byte[] EnableAutomaticStatusBack();
|
||||
|
||||
byte[] EnableAutomaticInkStatusBack();
|
||||
|
||||
/* Barcode Commands */
|
||||
byte[] PrintBarcode(BarcodeType type, string barcode, BarcodeCode code = BarcodeCode.CODE_B);
|
||||
|
||||
byte[] PrintQRCode(string data, TwoDimensionCodeType type = TwoDimensionCodeType.QRCODE_MODEL2, Size2DCode size = Size2DCode.NORMAL, CorrectionLevel2DCode correction = CorrectionLevel2DCode.PERCENT_7);
|
||||
|
||||
byte[] Print2DCode(TwoDimensionCodeType type, string data, Size2DCode size = Size2DCode.NORMAL, CorrectionLevel2DCode correction = CorrectionLevel2DCode.PERCENT_7);
|
||||
|
||||
byte[] SetBarcodeHeightInDots(int height);
|
||||
|
||||
byte[] SetBarWidth(BarWidth width);
|
||||
|
||||
byte[] SetBarLabelPosition(BarLabelPrintPosition position);
|
||||
|
||||
byte[] SetBarLabelFontB(bool fontB);
|
||||
|
||||
/* 2D-Code Commands */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace SixLabors.ImageSharp
|
||||
{
|
||||
public static class ImageSharpExtensions
|
||||
{
|
||||
public static byte[] ToSingleBitPixelByteArray(this Image<Rgba32> image, bool rasterFormat = true, int? maxWidth = null, int? maxHeight = null, float threshold = 0.5F)
|
||||
{
|
||||
image.Mutate(img =>
|
||||
{
|
||||
if (maxWidth.HasValue || maxHeight.HasValue)
|
||||
{
|
||||
img.Resize(new ResizeOptions
|
||||
{
|
||||
Mode = ResizeMode.Max,
|
||||
Size = new Size(maxWidth ?? int.MaxValue, maxHeight ?? int.MaxValue),
|
||||
});
|
||||
}
|
||||
|
||||
img.BackgroundColor(Color.White);
|
||||
img.Grayscale().BinaryDither(KnownDitherings.Stucki);
|
||||
|
||||
if (!rasterFormat)
|
||||
{
|
||||
img.Rotate(RotateMode.Rotate90);
|
||||
img.Flip(FlipMode.Horizontal);
|
||||
}
|
||||
});
|
||||
|
||||
var result = image.ToSingleBitPixelByteArray();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static byte[] ToSingleBitPixelByteArray(this Image<Rgba32> image)
|
||||
{
|
||||
var bytesPerRow = (image.Width + 7 & -8) / 8;
|
||||
|
||||
var result = new byte[bytesPerRow * image.Height];
|
||||
for (int y = 0; y < image.Height; y++)
|
||||
{
|
||||
var row = image.GetPixelRowSpan(y);
|
||||
var rowStartPosition = y * bytesPerRow;
|
||||
|
||||
for (int x = 0; x < row.Length; x++)
|
||||
{
|
||||
if (!row[x].IsBlack())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result[rowStartPosition + (x / 8)] |= (byte)(0x01 << (7 - (x % 8)));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsBlack(this Rgba32 rgba)
|
||||
{
|
||||
return rgba.R == 0 && rgba.G == 0 && rgba.B == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ESCPOS_NET.Extensions
|
||||
{
|
||||
public static class TaskExtensions
|
||||
{
|
||||
public static void LogExceptions(this Task task)
|
||||
{
|
||||
task.ContinueWith(t =>
|
||||
{
|
||||
var aggException = t.Exception.Flatten();
|
||||
foreach (var exception in aggException.InnerExceptions)
|
||||
{
|
||||
Logging.Logger?.LogError(exception, "Uncaught Thread Exception.");
|
||||
}
|
||||
},
|
||||
TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ESCPOS_NET.Extensions
|
||||
{
|
||||
public static class Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds to the list of T items and/or enumerables of T. All other types will be ignored and not added to the list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">List's items type.</typeparam>
|
||||
/// <param name="list">List to be added the items.</param>
|
||||
/// <param name="items">Items to be added.</param>
|
||||
/// <returns>True if no item was ignored, otherwise False.</returns>
|
||||
public static bool AddRange<T>(this List<T> list, params object[] items)
|
||||
{
|
||||
bool ignoredItems = false;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is T itemT)
|
||||
{
|
||||
list.Add(itemT);
|
||||
}
|
||||
else if (item is IEnumerable<T> arrayT)
|
||||
{
|
||||
list.AddRange(arrayT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoredItems = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !ignoredItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1200:Using directives should be placed correctly", Justification = "Placing usings within namespaces is not default in VS or in generated code.")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this", Justification = "Visual Studio by default recommends removing prefixed 'this'.")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:Field names should not begin with underscore", Justification = "MS style guide uses _ for private members.")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1025:Code should not contain multiple whitespace in a row", Justification = "<Pending>", Scope = "type", Target = "~T:ESCPOS_NET.Emitters.CodePage")]
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Luke Paireepinart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,19 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ESCPOS_NET
|
||||
{
|
||||
public static class Logging
|
||||
{
|
||||
public static ILogger Logger { get; set; }
|
||||
static Logging()
|
||||
{
|
||||
|
||||
TaskScheduler.UnobservedTaskException += (s, e) =>
|
||||
{
|
||||
//LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
|
||||
e.SetObserved();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
using ESCPOS_NET.Emitters.BaseCommandValues;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using ESCPOS_NET.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
|
||||
namespace ESCPOS_NET
|
||||
{
|
||||
public abstract partial class BasePrinter : IPrinter, IDisposable
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
//private volatile bool _isMonitoring;
|
||||
|
||||
private CancellationTokenSource _readCancellationTokenSource;
|
||||
private CancellationTokenSource _writeCancellationTokenSource;
|
||||
|
||||
private readonly int _maxBytesPerWrite = 15000; // max byte chunks to write at once.
|
||||
|
||||
public PrinterStatusEventArgs Status { get; private set; } = new PrinterStatusEventArgs();
|
||||
|
||||
public event EventHandler StatusChanged;
|
||||
public event EventHandler Disconnected;
|
||||
public event EventHandler Connected;
|
||||
//public event EventHandler WriteFailed;
|
||||
//public event EventHandler Idle;
|
||||
|
||||
protected BinaryWriter Writer { get; set; }
|
||||
|
||||
protected BinaryReader Reader { get; set; }
|
||||
|
||||
protected ConcurrentQueue<byte> ReadBuffer { get; set; } = new ConcurrentQueue<byte>();
|
||||
|
||||
protected ConcurrentQueue<byte[]> WriteBuffer { get; set; } = new ConcurrentQueue<byte[]>();
|
||||
|
||||
protected int BytesWrittenSinceLastFlush { get; set; } = 0;
|
||||
|
||||
protected volatile bool IsConnected = true;
|
||||
|
||||
public string PrinterName { get; protected set; }
|
||||
|
||||
protected BasePrinter()
|
||||
{
|
||||
PrinterName = Guid.NewGuid().ToString();
|
||||
Init();
|
||||
}
|
||||
protected BasePrinter(string printerName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(printerName))
|
||||
{
|
||||
printerName = Guid.NewGuid().ToString();
|
||||
}
|
||||
PrinterName = printerName;
|
||||
Init();
|
||||
}
|
||||
private void Init()
|
||||
{
|
||||
_readCancellationTokenSource = new CancellationTokenSource();
|
||||
_writeCancellationTokenSource = new CancellationTokenSource();
|
||||
Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Initializing Task Threads...", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
//Task.Factory.StartNew(MonitorPrinterStatusLongRunningTask, _connectivityCancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
|
||||
Task.Factory.StartNew(WriteLongRunningTask, _writeCancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
|
||||
Task.Factory.StartNew(ReadLongRunningTask, _readCancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
|
||||
// TODO: read and status monitoring probably won't work for fileprinter, should let printer types disable this feature.
|
||||
Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Task Threads started", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
|
||||
|
||||
protected void InvokeConnect()
|
||||
{
|
||||
Task.Run(() => Connected?.Invoke(this, new ConnectionEventArgs() { IsConnected = true }));
|
||||
}
|
||||
protected void InvokeDisconnect()
|
||||
{
|
||||
Task.Run(() => Disconnected?.Invoke(this, new ConnectionEventArgs() { IsConnected = false }));
|
||||
}
|
||||
|
||||
protected virtual void Reconnect()
|
||||
{
|
||||
// Implemented in the network printer
|
||||
}
|
||||
protected virtual async void WriteLongRunningTask()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_writeCancellationTokenSource != null && _writeCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Write Long-Running Task Cancellation was requested.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
if (!IsConnected)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var didDequeue = WriteBuffer.TryDequeue(out var nextBytes);
|
||||
if (didDequeue && nextBytes?.Length > 0)
|
||||
{
|
||||
WriteToBinaryWriter(nextBytes);
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
// Thrown if the printer times out the socket connection
|
||||
// default is 90 seconds
|
||||
//Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Swallowing IOException... sometimes happens with network printers. Should get reconnected automatically.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Swallow the exception
|
||||
//Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Swallowing generic read exception... sometimes happens with serial port printers.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual async void ReadLongRunningTask()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_readCancellationTokenSource != null && _readCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Read Long-Running Task Cancellation was requested.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
|
||||
if (Reader == null) continue;
|
||||
if (!IsConnected) continue;
|
||||
|
||||
try
|
||||
{
|
||||
// Sometimes the serial port lib will throw an exception and read past the end of the queue if a
|
||||
// status changes while data is being written. We just ignore these bytes.
|
||||
var b = Reader.BaseStream.ReadByte();
|
||||
if (b >= 0 && b <= 255)
|
||||
{
|
||||
ReadBuffer.Enqueue((byte)b);
|
||||
DataAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Swallow the exception
|
||||
//Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Swallowing generic read exception... sometimes happens with serial port printers.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Write(params byte[][] arrays)
|
||||
{
|
||||
Write(ByteSplicer.Combine(arrays));
|
||||
}
|
||||
|
||||
public virtual void Write(byte[] bytes)
|
||||
{
|
||||
WriteBuffer.Enqueue(bytes);
|
||||
}
|
||||
|
||||
protected virtual void WriteToBinaryWriter(byte[] bytes)
|
||||
{
|
||||
|
||||
if (!IsConnected)
|
||||
{
|
||||
Logging.Logger?.LogInformation("[{Function}]:[{PrinterName}] Attempted to write but printer isn't connected. Attempting to reconnect...", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
Reconnect();
|
||||
}
|
||||
|
||||
if (!IsConnected)
|
||||
{
|
||||
Logging.Logger?.LogError("[{Function}]:[{PrinterName}] Unrecoverable connectivity error writing to printer.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
throw new IOException("Unrecoverable connectivity error writing to printer.");
|
||||
}
|
||||
|
||||
int bytePointer = 0;
|
||||
int bytesLeft = bytes.Length;
|
||||
bool hasFlushed = false;
|
||||
while (bytesLeft > 0)
|
||||
{
|
||||
|
||||
int count = Math.Min(_maxBytesPerWrite, bytesLeft);
|
||||
try
|
||||
{
|
||||
Writer.Write(bytes, bytePointer, count);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Reconnect();
|
||||
if (!IsConnected)
|
||||
{
|
||||
Logging.Logger?.LogError(e, "[{Function}]:[{PrinterName}] Unrecoverable connectivity error writing to printer.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
Writer.Write(bytes, bytePointer, count);
|
||||
}
|
||||
BytesWrittenSinceLastFlush += count;
|
||||
if (BytesWrittenSinceLastFlush >= 200)
|
||||
{
|
||||
// Immediately trigger a flush before proceeding so the output buffer will not be delayed.
|
||||
hasFlushed = true;
|
||||
Flush(null, null);
|
||||
}
|
||||
|
||||
bytePointer += count;
|
||||
bytesLeft -= count;
|
||||
}
|
||||
|
||||
if (!hasFlushed)
|
||||
{
|
||||
Task.Run(async () => { await Task.Delay(50); Flush(null, null); });
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Flush(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
BytesWrittenSinceLastFlush = 0;
|
||||
Writer.Flush();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Logger?.LogError(ex, "[{Function}]:[{PrinterName}] Flush threw exception.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DataAvailable()
|
||||
{
|
||||
if (ReadBuffer.Count() % 4 == 0)
|
||||
{
|
||||
var bytes = new byte[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (!ReadBuffer.TryDequeue(out bytes[i]))
|
||||
{
|
||||
// Ran out of bytes unexpectedly.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TryUpdatePrinterStatus(bytes);
|
||||
|
||||
// TODO: call other update handlers.
|
||||
}
|
||||
}
|
||||
|
||||
private void TryUpdatePrinterStatus(byte[] bytes)
|
||||
{
|
||||
var bytesToString = BitConverter.ToString(bytes);
|
||||
|
||||
Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] TryUpdatePrinterStatus: Received flag values {bytesToString}", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName, bytesToString);
|
||||
|
||||
// Check header bits 0, 1 and 7 are 0, and 4 is 1
|
||||
if (bytes[0].IsBitNotSet(0) && bytes[0].IsBitNotSet(1) && bytes[0].IsBitSet(4) && bytes[0].IsBitNotSet(7))
|
||||
{
|
||||
Status = new PrinterStatusEventArgs()
|
||||
{
|
||||
// byte[0] == 20 cash drawer closed
|
||||
// byte[0] == 16 cash drawer open
|
||||
// Note some cash drawers do not close properly.
|
||||
IsCashDrawerOpen = bytes[0].IsBitNotSet(2),
|
||||
IsPrinterOnline = bytes[0].IsBitNotSet(3),
|
||||
IsCoverOpen = bytes[0].IsBitSet(5),
|
||||
IsPaperCurrentlyFeeding = bytes[0].IsBitSet(6),
|
||||
IsWaitingForOnlineRecovery = bytes[1].IsBitSet(0),
|
||||
IsPaperFeedButtonPushed = bytes[1].IsBitSet(1),
|
||||
DidRecoverableNonAutocutterErrorOccur = bytes[1].IsBitSet(2),
|
||||
DidAutocutterErrorOccur = bytes[1].IsBitSet(3),
|
||||
DidUnrecoverableErrorOccur = bytes[1].IsBitSet(5),
|
||||
DidRecoverableErrorOccur = bytes[1].IsBitSet(6),
|
||||
IsPaperLow = bytes[2].IsBitSet(0) && bytes[2].IsBitSet(1),
|
||||
IsPaperOut = bytes[2].IsBitSet(2) && bytes[2].IsBitSet(3),
|
||||
};
|
||||
}
|
||||
|
||||
if (StatusChanged != null)
|
||||
{
|
||||
Logging.Logger?.LogDebug("[{Function}]:[{PrinterName}] Invoking Status Changed Event Handler...", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
StatusChanged?.Invoke(this, Status);
|
||||
}
|
||||
}
|
||||
|
||||
~BasePrinter()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void OverridableDispose() // This method should only be called by the Dispose method. // It allows synchronous disposing of derived class dependencies with base class disposes.
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
_readCancellationTokenSource?.Cancel();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Logger?.LogDebug(e, "[{Function}]:[{PrinterName}] Dispose Issue during cancellation token cancellation call.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
try
|
||||
{
|
||||
Reader?.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Logger?.LogDebug(e, "[{Function}]:[{PrinterName}] Dispose Issue closing reader.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
try
|
||||
{
|
||||
Reader?.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Logger?.LogDebug(e, "[{Function}]:[{PrinterName}] Dispose Issue disposing reader.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
try
|
||||
{
|
||||
Writer?.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Logger?.LogDebug(e, "[{Function}]:[{PrinterName}] Dispose Issue closing writer.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
try
|
||||
{
|
||||
Writer?.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Logger?.LogDebug(e, "[{Function}]:[{PrinterName}] Dispose Issue disposing writer.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
try
|
||||
{
|
||||
OverridableDispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Logger?.LogDebug(e, "[{Function}]:[{PrinterName}] Dispose Issue during overridable dispose.", $"{this}.{MethodBase.GetCurrentMethod().Name}", PrinterName);
|
||||
}
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public PrinterStatusEventArgs GetStatus()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace ESCPOS_NET
|
||||
{
|
||||
public class ConnectionEventArgs : EventArgs
|
||||
{
|
||||
public bool IsConnected;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.IO;
|
||||
|
||||
namespace ESCPOS_NET
|
||||
{
|
||||
public class FilePrinter : BasePrinter
|
||||
{
|
||||
private readonly FileStream _file;
|
||||
|
||||
// TODO: default values to their default values in ctor.
|
||||
public FilePrinter(string filePath, bool createIfNotExists = false)
|
||||
: base()
|
||||
{
|
||||
if (createIfNotExists)
|
||||
{
|
||||
_file = File.Open(filePath, FileMode.OpenOrCreate);
|
||||
}
|
||||
else
|
||||
{
|
||||
_file = File.Open(filePath, FileMode.Open);
|
||||
}
|
||||
Writer = new BinaryWriter(_file);
|
||||
Reader = new BinaryReader(_file);
|
||||
}
|
||||
|
||||
~FilePrinter()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
protected override void OverridableDispose()
|
||||
{
|
||||
_file?.Close();
|
||||
_file?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace ESCPOS_NET
|
||||
{
|
||||
public interface IPrinter
|
||||
{
|
||||
PrinterStatusEventArgs GetStatus();
|
||||
void Write(params byte[][] arrays);
|
||||
void Write(byte[] bytes);
|
||||
event EventHandler StatusChanged;
|
||||
event EventHandler Disconnected;
|
||||
event EventHandler Connected;
|
||||
//event EventHandler WriteFailed;
|
||||
//event EventHandler Idle;
|
||||
//event EventHandler IdleDisconnected; is this useful? to know that it disconnected because of idle? probably better to have this as info in disconnected event object instead.
|
||||
}
|
||||
}
|
||||