Print problemer
Har muligvis rettet den print fejl der er - men mangler at få det testet. Der er slettet en masse projekter som ikke bliver brugt mere. Og flyttet rundt på de få projekter som er tilbage. Dette er V2 og i sit eget repo, så dette er initial commit
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
################################################################################
|
||||
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||
################################################################################
|
||||
|
||||
/.vs/PointOfSale/FileContentIndex
|
||||
362
PointOfSale/.gitignore
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
9
PointOfSale/EpsonPrinterLinux/Enums/AlignmentEnum.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace EpsonPrinter.Enums
|
||||
{
|
||||
public enum AlignmentEnum
|
||||
{
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
}
|
||||
}
|
||||
12
PointOfSale/EpsonPrinterLinux/Enums/PrintStylesEnum.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace EpsonPrinter.Enums
|
||||
{
|
||||
public enum PrintStylesEnum
|
||||
{
|
||||
None,
|
||||
FontB,
|
||||
Bold,
|
||||
DoubleHeight,
|
||||
DoubleWidth,
|
||||
UnderLine
|
||||
}
|
||||
}
|
||||
23
PointOfSale/EpsonPrinterLinux/EpsonPrinter.csproj
Normal file
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerfileContext>..\Pos</DockerfileContext>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="ESC-POS\**" />
|
||||
<Content Remove="ESC-POS\**" />
|
||||
<EmbeddedResource Remove="ESC-POS\**" />
|
||||
<None Remove="ESC-POS\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ESCPOS_NET" Version="3.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
PointOfSale/EpsonPrinterLinux/Model/BodyModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class BodyModel
|
||||
{
|
||||
public List<BodyProductModel> Products { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
public decimal TotalVat { get; set; }
|
||||
public int ReceiptNumber { get; set; }
|
||||
public string ReceiptTime { get; set; }
|
||||
public string Staff { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
15
PointOfSale/EpsonPrinterLinux/Model/BodyProductModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class BodyProductModel
|
||||
{
|
||||
public string Product { get; set; }
|
||||
public int NoOfProduct { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public decimal TotalPrice { get; set; }
|
||||
}
|
||||
}
|
||||
16
PointOfSale/EpsonPrinterLinux/Model/FooterModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Enums;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class FooterModel
|
||||
{
|
||||
public string Value { get; set; }
|
||||
public PrintStyleModel PrintStyles { get; set; }
|
||||
public AlignmentEnum TextAlignment { get; set; }
|
||||
public int FeedingLines { get; set; }
|
||||
}
|
||||
}
|
||||
16
PointOfSale/EpsonPrinterLinux/Model/HeaderModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Enums;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class HeaderModel
|
||||
{
|
||||
public string Value { get; set; }
|
||||
public PrintStyleModel PrintStyles { get; set; }
|
||||
public AlignmentEnum TextAlignment { get; set; }
|
||||
public int FeedingLines { get; set; }
|
||||
}
|
||||
}
|
||||
16
PointOfSale/EpsonPrinterLinux/Model/PrintStyleModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class PrintStyleModel
|
||||
{
|
||||
public bool FontB { get; set; }
|
||||
public bool Bold { get; set; }
|
||||
public bool DoubleHeight { get; set; }
|
||||
public bool DoubleWidth { get; set; }
|
||||
public bool Underline { get; set; }
|
||||
}
|
||||
}
|
||||
13
PointOfSale/EpsonPrinterLinux/Model/ReceiptModel.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class ReceiptModel
|
||||
{
|
||||
public string LogoBase64 { get; set; }
|
||||
public List<HeaderModel> Header { get; set; }
|
||||
public BodyModel BodyModel { get; set; }
|
||||
public List<FooterModel> Footer { get; set; }
|
||||
}
|
||||
}
|
||||
10
PointOfSale/EpsonPrinterLinux/Model/SaleOfDayDetail.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class SaleOfDayDetail
|
||||
{
|
||||
public string Category { get; set; }
|
||||
public decimal TotalSale { get; set; }
|
||||
}
|
||||
}
|
||||
14
PointOfSale/EpsonPrinterLinux/Model/SaleOfDayModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace EpsonPrinter.Model
|
||||
{
|
||||
public class SaleOfDayModel
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public int TotalCustomers { get; set; }
|
||||
public Decimal TotalSale { get; set; }
|
||||
public List<SaleOfDayDetail> SaleOfDayDetail { get; set; } = new();
|
||||
|
||||
}
|
||||
}
|
||||
23
PointOfSale/EpsonPrinterLinux/Program.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using EpsonPrinter.Services;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Services
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
builder.Services.AddScoped<EpsonPrintService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Swagger (altid aktiv – vi er på en Pi, ikke i produktion)
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
// Routing
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
31
PointOfSale/EpsonPrinterLinux/Properties/launchSettings.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:23653",
|
||||
"sslPort": 44334
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"EpsonPrinter": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
PointOfSale/EpsonPrinterLinux/README_LINUX_USB.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
Linux USB version of the EpsonPrinter API.
|
||||
|
||||
What changed:
|
||||
- Keeps the incoming JSON models for /api/PosPrinter/Receipt and /api/PosPrinter/SaleOfDay
|
||||
- Replaces COM/SerialPrinter transport with raw writes to Linux USB printer device
|
||||
- Uses /dev/usb/lp0 by default from appsettings.json
|
||||
- Builds a standard receipt when parts of the payload are missing
|
||||
- Pulls fallback values from appsettings.json under PrintSettings:Defaults
|
||||
|
||||
Typical run:
|
||||
dotnet restore
|
||||
dotnet run
|
||||
|
||||
Typical endpoint:
|
||||
POST /api/PosPrinter/Receipt
|
||||
|
||||
Important setting:
|
||||
PrintSettings:DevicePath = /dev/usb/lp0
|
||||
306
PointOfSale/EpsonPrinterLinux/Services/EpsonPrintService.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET;
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class EpsonPrintService
|
||||
{
|
||||
private readonly IConfiguration _config;
|
||||
private readonly string _devicePath;
|
||||
private readonly string? _previewPath;
|
||||
private readonly bool _isDevelopment;
|
||||
|
||||
public EpsonPrintService(IConfiguration config, IWebHostEnvironment environment)
|
||||
{
|
||||
_config = config;
|
||||
_isDevelopment = environment.IsDevelopment();
|
||||
|
||||
var configuredPath = _config["PrintSettings:DevicePath"] ?? "/dev/usb/lp0";
|
||||
_devicePath = _isDevelopment && !Path.IsPathRooted(configuredPath)
|
||||
? Path.Combine(environment.ContentRootPath, configuredPath)
|
||||
: configuredPath;
|
||||
|
||||
var configuredPreviewPath = _config["PrintSettings:PreviewPath"] ?? "printer-preview.txt";
|
||||
_previewPath = _isDevelopment
|
||||
? Path.IsPathRooted(configuredPreviewPath)
|
||||
? configuredPreviewPath
|
||||
: Path.Combine(environment.ContentRootPath, configuredPreviewPath)
|
||||
: null;
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
}
|
||||
|
||||
public void PrintReceipt(ReceiptModel model)
|
||||
{
|
||||
ICommandEmitter e = new EPSON();
|
||||
InitAndWrite(e);
|
||||
|
||||
List<byte[][]> printBytes = new List<byte[][]>();
|
||||
PrintHeader printHeader = new PrintHeader(e);
|
||||
PrintBody printBody = new PrintBody(e, _config);
|
||||
PrintFooter printFooter = new PrintFooter(e);
|
||||
|
||||
var header = (model.Header != null && model.Header.Any()) ? model.Header : BuildDefaultHeader();
|
||||
var body = model.BodyModel ?? BuildDefaultBody();
|
||||
if (string.IsNullOrWhiteSpace(body.Staff))
|
||||
{
|
||||
body.Staff = _config["PrintSettings:Defaults:Staff"] ?? "Ukendt";
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(body.ReceiptTime))
|
||||
{
|
||||
body.ReceiptTime = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss");
|
||||
}
|
||||
if (body.ReceiptNumber <= 0)
|
||||
{
|
||||
body.ReceiptNumber = Math.Abs(Environment.TickCount % 1000000);
|
||||
}
|
||||
body.Products ??= new List<BodyProductModel>();
|
||||
if (!body.Products.Any())
|
||||
{
|
||||
body.Products.Add(new BodyProductModel
|
||||
{
|
||||
Product = "Standard vare",
|
||||
NoOfProduct = 1,
|
||||
Price = 99.00m,
|
||||
TotalPrice = 99.00m
|
||||
});
|
||||
}
|
||||
if (body.TotalPrice <= 0)
|
||||
{
|
||||
body.TotalPrice = body.Products.Sum(x => x.TotalPrice <= 0 ? x.Price * x.NoOfProduct : x.TotalPrice);
|
||||
}
|
||||
if (body.TotalVat <= 0)
|
||||
{
|
||||
body.TotalVat = Math.Round(body.TotalPrice * 0.25m, 2);
|
||||
}
|
||||
|
||||
var footer = (model.Footer != null && model.Footer.Any()) ? model.Footer : BuildDefaultFooter();
|
||||
|
||||
printBytes.AddRange(printHeader.Print(header));
|
||||
printBytes.AddRange(printBody.Print(body));
|
||||
printBytes.AddRange(printFooter.Print(footer));
|
||||
|
||||
byte[][] array = printBytes.SelectMany(c => c).ToArray();
|
||||
Write(array);
|
||||
Write(e.FeedLines(5));
|
||||
Write(e.FullCut());
|
||||
}
|
||||
|
||||
public void PrintSaleOfDay(SaleOfDayModel model)
|
||||
{
|
||||
ICommandEmitter e = new EPSON();
|
||||
InitAndWrite(e);
|
||||
PrintSaleOfDay(model, e);
|
||||
}
|
||||
|
||||
private void InitAndWrite(ICommandEmitter e)
|
||||
{
|
||||
Write(e.Initialize());
|
||||
Write(e.Enable());
|
||||
Write(e.CodePage(CodePage.ISO8859_15_LATIN9));
|
||||
Write(e.EnableAutomaticStatusBack());
|
||||
}
|
||||
|
||||
private void PrintSaleOfDay(SaleOfDayModel model, ICommandEmitter e)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
|
||||
byte[][] dateBytes =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine($"Dato: {model.Date:dd-MM-yyyy}")
|
||||
};
|
||||
data.Add(dateBytes);
|
||||
|
||||
byte[][] seperater =
|
||||
{
|
||||
e.SetStyles(PrintStyle.None),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine("-----------------------------------")
|
||||
};
|
||||
data.Add(seperater);
|
||||
|
||||
foreach (SaleOfDayDetail saleOfDayDetail in model.SaleOfDayDetail)
|
||||
{
|
||||
string pS = $"{saleOfDayDetail.Category} : {saleOfDayDetail.TotalSale.ToString("#.#0", CultureInfo.InvariantCulture)}";
|
||||
byte[][] totalPrice =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine(pS)
|
||||
};
|
||||
data.Add(totalPrice);
|
||||
}
|
||||
|
||||
data.Add(seperater);
|
||||
|
||||
string totalSale = $"Total salg: {model.TotalSale.ToString("#.#0", CultureInfo.InvariantCulture)}";
|
||||
byte[][] tSBytes =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine(totalSale)
|
||||
};
|
||||
data.Add(tSBytes);
|
||||
|
||||
string totalCustomer = $"Antal kunder: {model.TotalCustomers}";
|
||||
byte[][] tCBytes =
|
||||
{
|
||||
e.SetStyles(PrintStyle.DoubleWidth),
|
||||
e.LeftAlign(),
|
||||
e.PrintLine(totalCustomer)
|
||||
};
|
||||
data.Add(tCBytes);
|
||||
|
||||
byte[][] array = data.SelectMany(c => c).ToArray();
|
||||
Write(array);
|
||||
Write(e.FeedLines(5));
|
||||
Write(e.FullCut());
|
||||
}
|
||||
|
||||
private List<HeaderModel> BuildDefaultHeader()
|
||||
{
|
||||
return new List<HeaderModel>
|
||||
{
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:StoreName"] ?? "TableTop3D",
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel { Bold = true, DoubleWidth = true, DoubleHeight = true }
|
||||
},
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:AddressLine1"] ?? string.Empty,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel { Bold = true }
|
||||
},
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:AddressLine2"] ?? string.Empty,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel()
|
||||
},
|
||||
new HeaderModel
|
||||
{
|
||||
Value = _config["PrintSettings:Defaults:Cvr"] ?? string.Empty,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 1,
|
||||
PrintStyles = new PrintStyleModel()
|
||||
}
|
||||
}.Where(x => !string.IsNullOrWhiteSpace(x.Value)).ToList();
|
||||
}
|
||||
|
||||
private FooterModel CreateFooterLine(string value, bool bold = false)
|
||||
{
|
||||
return new FooterModel
|
||||
{
|
||||
Value = value,
|
||||
TextAlignment = Enums.AlignmentEnum.Center,
|
||||
FeedingLines = 0,
|
||||
PrintStyles = new PrintStyleModel { Bold = bold }
|
||||
};
|
||||
}
|
||||
|
||||
private List<FooterModel> BuildDefaultFooter()
|
||||
{
|
||||
var values = new[]
|
||||
{
|
||||
_config["PrintSettings:Defaults:FooterLine1"] ?? "Tak for dit køb!",
|
||||
_config["PrintSettings:Defaults:FooterLine2"] ?? string.Empty,
|
||||
_config["PrintSettings:Defaults:Phone"] ?? string.Empty
|
||||
}.Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
||||
|
||||
return values.Select((x, i) => CreateFooterLine(x, i == 0)).ToList();
|
||||
}
|
||||
|
||||
private BodyModel BuildDefaultBody()
|
||||
{
|
||||
return new BodyModel
|
||||
{
|
||||
ReceiptNumber = Math.Abs(Environment.TickCount % 1000000),
|
||||
ReceiptTime = DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss"),
|
||||
Staff = _config["PrintSettings:Defaults:Staff"] ?? "Ukendt",
|
||||
Products = new List<BodyProductModel>
|
||||
{
|
||||
new BodyProductModel
|
||||
{
|
||||
Product = "Standard vare",
|
||||
NoOfProduct = 1,
|
||||
Price = 99.00m,
|
||||
TotalPrice = 99.00m
|
||||
}
|
||||
},
|
||||
TotalPrice = 99.00m,
|
||||
TotalVat = 24.75m
|
||||
};
|
||||
}
|
||||
|
||||
private void Write(byte[] data)
|
||||
{
|
||||
var fileMode = _isDevelopment ? FileMode.Append : FileMode.Open;
|
||||
using var stream = new FileStream(_devicePath, fileMode, FileAccess.Write, FileShare.ReadWrite);
|
||||
stream.Write(data, 0, data.Length);
|
||||
stream.Flush();
|
||||
|
||||
if (_previewPath != null)
|
||||
{
|
||||
AppendPreview(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendPreview(byte[] data)
|
||||
{
|
||||
using var writer = new StreamWriter(_previewPath!, append: true, Encoding.UTF8);
|
||||
var textEncoding = Encoding.GetEncoding("iso-8859-15");
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
byte value = data[i];
|
||||
if (value == 0x1B)
|
||||
{
|
||||
i += i + 1 < data.Length && data[i + 1] == 0x40 ? 1 : 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value == 0x1D)
|
||||
{
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value == 0x0A)
|
||||
{
|
||||
writer.WriteLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value >= 0x20)
|
||||
{
|
||||
writer.Write(textEncoding.GetString(new[] { value }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Write(byte[][] data)
|
||||
{
|
||||
foreach (var segment in data)
|
||||
{
|
||||
Write(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
PointOfSale/EpsonPrinterLinux/Services/PrintAlignment.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using EpsonPrinter.Enums;
|
||||
using ESCPOS_NET.Emitters;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintAlignment
|
||||
{
|
||||
public byte[] GetTextAlignment(ICommandEmitter e, AlignmentEnum alignment)
|
||||
{
|
||||
if (alignment == AlignmentEnum.Left)
|
||||
return e.LeftAlign();
|
||||
|
||||
if (alignment == AlignmentEnum.Right)
|
||||
return e.RightAlign();
|
||||
|
||||
return e.CenterAlign();
|
||||
}
|
||||
}
|
||||
}
|
||||
117
PointOfSale/EpsonPrinterLinux/Services/PrintBody.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET.Emitters;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintBody
|
||||
{
|
||||
private ICommandEmitter _e;
|
||||
private IConfiguration _config;
|
||||
|
||||
private int productMaxWidth;
|
||||
|
||||
public PrintBody(ICommandEmitter e, IConfiguration config)
|
||||
{
|
||||
_e = e;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public List<byte[][]> Print(BodyModel model)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
|
||||
byte[][] headerModel =
|
||||
{
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
_e.LeftAlign(),
|
||||
_e.PrintLine($"Dato.........: {model.ReceiptTime}"),
|
||||
_e.PrintLine($"Ekspedient...: {model.Staff}"),
|
||||
_e.PrintLine($"Kvittering...: {model.ReceiptNumber}"),
|
||||
_e.FeedLines(1)
|
||||
};
|
||||
data.Add(headerModel);
|
||||
|
||||
int printWidth = Convert.ToInt32(_config["PrintSettings:PrintWidth"]);
|
||||
foreach (BodyProductModel product in model.Products)
|
||||
{
|
||||
//Size of product is max half of recipt
|
||||
string totalProductLine = MakeProductNameString(product.Product, printWidth);
|
||||
totalProductLine += MakeProductNumber(product.NoOfProduct, product.Price);
|
||||
totalProductLine = MakeTotalProductPrice(totalProductLine, product.TotalPrice,printWidth);
|
||||
|
||||
byte[][] p =
|
||||
{
|
||||
_e.PrintLine(totalProductLine)
|
||||
};
|
||||
data.Add(p);
|
||||
}
|
||||
|
||||
PrintString printString = new PrintString();
|
||||
string totalPricePrint = printString.MakePrintString(printWidth, $"Total: ", $"{model.TotalPrice:F} DKK");
|
||||
byte[][] totalPrice =
|
||||
{
|
||||
_e.FeedLines(1),
|
||||
_e.SetStyles(PrintStyle.Bold | PrintStyle.DoubleHeight),
|
||||
_e.RightAlign(),
|
||||
_e.PrintLine(totalPricePrint)
|
||||
};
|
||||
data.Add(totalPrice);
|
||||
|
||||
byte[][] vat =
|
||||
{
|
||||
_e.FeedLines(1),
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
_e.LeftAlign(),
|
||||
_e.PrintLine(MakeVat(printWidth,model.TotalVat))
|
||||
};
|
||||
data.Add(vat);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private string MakeProductNameString(string product, int totalWidth)
|
||||
{
|
||||
string productString = product;
|
||||
productMaxWidth = (totalWidth / 2) - 5;
|
||||
int productLength = product.Length;
|
||||
if (productLength < productMaxWidth)
|
||||
{
|
||||
|
||||
for (int i = productLength; i < productMaxWidth; i++)
|
||||
{
|
||||
productString += ".";
|
||||
}
|
||||
}
|
||||
|
||||
return productString;
|
||||
}
|
||||
|
||||
private string MakeProductNumber(int noOfProduct, decimal price)
|
||||
{
|
||||
return $"{noOfProduct} á {price:F} DKK :";
|
||||
}
|
||||
|
||||
private string MakeTotalProductPrice(string buffer, decimal totalPrice, int printWidth)
|
||||
{
|
||||
PrintString printString = new PrintString();
|
||||
string p = $"{totalPrice:F} DKK";
|
||||
string makePrintString = printString.MakePrintString(printWidth, buffer, p);
|
||||
return makePrintString;
|
||||
}
|
||||
|
||||
private string MakeVat(int printWidth, decimal vat)
|
||||
{
|
||||
PrintString printString = new PrintString();
|
||||
string vatDesc = $"Moms udgør 25% :";
|
||||
string v = $"{vat:F} DKK";
|
||||
string vatString = printString.MakePrintString(printWidth, vatDesc, v);
|
||||
return vatString;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
PointOfSale/EpsonPrinterLinux/Services/PrintFooter.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET;
|
||||
using ESCPOS_NET.Emitters;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintFooter
|
||||
{
|
||||
private ICommandEmitter _e;
|
||||
|
||||
public PrintFooter(ICommandEmitter e)
|
||||
{
|
||||
_e = e;
|
||||
}
|
||||
|
||||
public List<byte[][]> Print(List<FooterModel> model)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
PrintStyleCombination printStyleCombination = new PrintStyleCombination();
|
||||
PrintAlignment printAlignment = new PrintAlignment();
|
||||
byte[][] feedLines =
|
||||
{
|
||||
_e.FeedLines(1)
|
||||
};
|
||||
data.Add(feedLines);
|
||||
foreach (FooterModel footerModel in model)
|
||||
{
|
||||
|
||||
PrintStyle printStyle = printStyleCombination.Combine(footerModel.PrintStyles);
|
||||
byte[][] bytes = {
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
printAlignment.GetTextAlignment(_e,footerModel.TextAlignment),
|
||||
_e.SetStyles(printStyle),
|
||||
_e.PrintLine(footerModel.Value),
|
||||
_e.FeedLines(footerModel.FeedingLines)
|
||||
};
|
||||
data.Add(bytes);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
PointOfSale/EpsonPrinterLinux/Services/PrintHeader.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET;
|
||||
using ESCPOS_NET.Emitters;
|
||||
using ESCPOS_NET.Utilities;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintHeader
|
||||
{
|
||||
private ICommandEmitter _e;
|
||||
|
||||
public PrintHeader(ICommandEmitter e)
|
||||
{
|
||||
_e = e;
|
||||
}
|
||||
|
||||
public List<Byte[][]> Print(List<HeaderModel> model)
|
||||
{
|
||||
List<byte[][]> data = new List<byte[][]>();
|
||||
PrintStyleCombination printStyleCombination = new PrintStyleCombination();
|
||||
PrintAlignment printAlignment = new PrintAlignment();
|
||||
foreach (HeaderModel headerModel in model)
|
||||
{
|
||||
|
||||
PrintStyle printStyle = printStyleCombination.Combine(headerModel.PrintStyles);
|
||||
byte[][] bytes = {
|
||||
_e.SetStyles(PrintStyle.None),
|
||||
printAlignment.GetTextAlignment(_e,headerModel.TextAlignment),
|
||||
_e.SetStyles(printStyle),
|
||||
_e.PrintLine(headerModel.Value),
|
||||
_e.FeedLines(headerModel.FeedingLines)
|
||||
};
|
||||
data.Add(bytes);
|
||||
}
|
||||
byte[][] feedLines =
|
||||
{
|
||||
_e.FeedLines(1)
|
||||
};
|
||||
data.Add(feedLines);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
PointOfSale/EpsonPrinterLinux/Services/PrintString.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintString
|
||||
{
|
||||
/// <summary>
|
||||
/// An appropriate interval is converted into the length of
|
||||
/// the tab about two texts. And make a printing data.
|
||||
/// </summary>
|
||||
/// <param name="iLineChars">
|
||||
/// The width of the territory which it prints on is converted into the number of
|
||||
/// characters, and that value is specified.
|
||||
/// </param>
|
||||
/// <param name="strBuf">
|
||||
/// It is necessary as an information for deciding the interval of the text.
|
||||
/// </param>
|
||||
/// <param name="strPrice">
|
||||
/// It is necessary as an information for deciding the interval of the text, too.
|
||||
/// </param>
|
||||
/// <returns>printing data.
|
||||
/// </returns>
|
||||
public String MakePrintString(int iLineChars, String strBuf, String strPrice)
|
||||
{
|
||||
int bufferWidth = Math.Max(0, iLineChars - strPrice.Length);
|
||||
if (strBuf.Length > bufferWidth)
|
||||
{
|
||||
strBuf = strBuf.Substring(0, bufferWidth);
|
||||
}
|
||||
|
||||
return strBuf.PadRight(bufferWidth) + strPrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using EpsonPrinter.Enums;
|
||||
using EpsonPrinter.Model;
|
||||
using ESCPOS_NET.Emitters;
|
||||
|
||||
namespace EpsonPrinter.Services
|
||||
{
|
||||
public class PrintStyleCombination
|
||||
{
|
||||
public PrintStyle Combine(PrintStyleModel printStyleModel)
|
||||
{
|
||||
|
||||
//Bold
|
||||
if (printStyleModel.Bold && !printStyleModel.DoubleHeight && !printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold;
|
||||
|
||||
if (printStyleModel.Bold && printStyleModel.DoubleHeight && !printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight;
|
||||
|
||||
if(printStyleModel.Bold && printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth;
|
||||
|
||||
if (printStyleModel.Bold && printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB;
|
||||
|
||||
if (printStyleModel.Bold && printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.Bold | PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//DoubleHeight
|
||||
if (printStyleModel.DoubleHeight && !printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight;
|
||||
|
||||
if (printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight | PrintStyle.DoubleWidth;
|
||||
|
||||
if (printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB;
|
||||
|
||||
if (printStyleModel.DoubleHeight && printStyleModel.DoubleWidth && printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.DoubleHeight | PrintStyle.DoubleWidth | PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//DoubleWidth
|
||||
if (printStyleModel.DoubleWidth && !printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleWidth;
|
||||
|
||||
if (printStyleModel.DoubleWidth && printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.DoubleWidth | PrintStyle.FontB;
|
||||
|
||||
if (printStyleModel.DoubleWidth && printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.DoubleWidth | PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//FontB
|
||||
if (printStyleModel.FontB && !printStyleModel.Underline)
|
||||
return PrintStyle.FontB;
|
||||
|
||||
if(printStyleModel.FontB && printStyleModel.Underline)
|
||||
return PrintStyle.FontB | PrintStyle.Underline;
|
||||
|
||||
//Underline
|
||||
if (printStyleModel.Underline)
|
||||
return PrintStyle.Underline;
|
||||
|
||||
return PrintStyle.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
PointOfSale/EpsonPrinterLinux/appsettings.Development.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"PrintSettings": {
|
||||
"DevicePath": "printer-output.bin",
|
||||
"PreviewPath": "printer-preview.txt"
|
||||
}
|
||||
}
|
||||
26
PointOfSale/EpsonPrinterLinux/appsettings.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"PrintSettings": {
|
||||
"DevicePath": "/dev/usb/lp0",
|
||||
"PrintWidth": 48,
|
||||
"CodePage": "ISO8859_15_LATIN9",
|
||||
"Defaults": {
|
||||
"StoreName": "Blomster Til Alt",
|
||||
"AddressLine1": "Adelgade 88",
|
||||
"AddressLine2": "5400 Bogense",
|
||||
"Cvr": "CVR: 37144436",
|
||||
"Phone": "Tlf: 41 82 71 66",
|
||||
"FooterLine1": "Tak for dit køb!",
|
||||
"FooterLine2": "Vi håber du bliver glad for dine varer.",
|
||||
"Staff": "Ukendt",
|
||||
"ReceiptPrefix": "BON"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
PointOfSale/EpsonPrinterLinux/printer-output.bin
Normal file
12
PointOfSale/EpsonPrinterLinux/printer-preview.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Blomster Til Alt
|
||||
Adelgade 91
|
||||
5400 Bogense
|
||||
Tlf: 41 82 71 66
|
||||
CVR: 37 14 44 36
|
||||
Dato.........: 22.26 15-07-2026
|
||||
Ekspedient...: Jette
|
||||
Kvittering...: 15781
|
||||
Buket..............1 á 50,50 DKK : 50,50 DKK
|
||||
Total: 50,50 DKK
|
||||
Moms udgør 25% : 12,63 DKK
|
||||
Tak for handlen
|
||||
73
PointOfSale/EpsonPrinterLinux/testdata.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"logoBase64": "string",
|
||||
"header": [
|
||||
{
|
||||
"value": "F<>rste linie med <20><><EFBFBD> <20><><EFBFBD>",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Anden linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Tredje linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Fjerde linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
},
|
||||
{
|
||||
"value": "Femte linie",
|
||||
"printStyles": {
|
||||
"fontB": false,
|
||||
"bold": true,
|
||||
"doubleHeight": false,
|
||||
"doubleWidth": false,
|
||||
"underline": false
|
||||
},
|
||||
"textAlignment": 0
|
||||
}
|
||||
],
|
||||
"footer": [
|
||||
{
|
||||
"value": "string",
|
||||
"printStyles": {
|
||||
"fontB": true,
|
||||
"bold": true,
|
||||
"doubleHeight": true,
|
||||
"doubleWidth": true,
|
||||
"underline": true
|
||||
},
|
||||
"textAlignment": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
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 };
|
||||
}
|
||||
}
|
||||