Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
9d6b9c5
Cross-platform port to Avalonia 12 + .NET 10 (barcodes/QR, serial, ex…
danielmeza Jun 5, 2026
97ada87
Fix macOS "damaged" error: ad-hoc code-sign the .app bundle (#2)
danielmeza Jun 5, 2026
bc6d3da
Fix Test print/Hex Dump in packaged app: resolve test_receipt.txt via…
danielmeza Jun 5, 2026
b988820
Give buzzer / cash-drawer real cross-platform feedback (sound + on-sc…
danielmeza Jun 5, 2026
8ffbcad
Add printer state model, bidirectional transport, status commands + s…
danielmeza Jun 6, 2026
d917bae
Add manufacturer buzzer, config no-ops, and PDF417/DataMatrix/Aztec 2…
danielmeza Jun 6, 2026
9b75cca
Add bit-image commands: ESC * inline raster, GS * define + GS / print
danielmeza Jun 6, 2026
3abe2cc
Add page mode (ESC L/S, FF, CAN) and positioning command parsing
danielmeza Jun 6, 2026
efe492a
Add code-page tables (ESC t) and user-defined characters (ESC & / % / ?)
danielmeza Jun 6, 2026
b6d09d9
Update README for status/state panel, page mode, 2D, bit-image, code …
danielmeza Jun 6, 2026
77557ed
Comprehensive test print: all text styles, barcodes, 2D symbols, bit …
danielmeza Jun 6, 2026
e812b13
Add Monitor window: ESC-POS-.NET client to exercise the emulator
danielmeza Jun 6, 2026
b4f0727
Printer reacts to ready-state; richer monitor status indicators
danielmeza Jun 6, 2026
bb1900a
Gate line feed when not ready so blocked prints leave no blank receipts
danielmeza Jun 6, 2026
65d73dd
Re-arm print-blocked notification per job so every blocked print noti…
danielmeza Jun 6, 2026
8d7e110
Treat warnings (incl. NuGet audit) as errors; fix all warnings; de-ma…
danielmeza Jun 6, 2026
c1ddc88
Toast stays longer (re-armable timer); move test responsibility to th…
danielmeza Jun 6, 2026
084f15f
Showcase the Monitor window in the README with screenshots
danielmeza Jun 6, 2026
bb68523
README: list ESC-POS-.NET (Monitor test client) in Built with
danielmeza Jun 6, 2026
ca4d767
Monitor can connect over serial as well as TCP
danielmeza Jun 6, 2026
765767a
Monitor: add direct USB printing (libusb) as a third transport
danielmeza Jun 6, 2026
fe8e6ae
Fix 'Unable to load libusb-1.0' by resolving the native lib at runtime
danielmeza Jun 6, 2026
6b72bbb
Monitor: clear libusb-not-found log with install steps; copyable acti…
danielmeza Jun 6, 2026
e8a9055
Fix libusb discovery: augment NATIVE_DLL_SEARCH_DIRECTORIES instead o…
danielmeza Jun 6, 2026
8206738
Monitor USB: bidirectional transport with status (UsbPrinter : BasePr…
danielmeza Jun 6, 2026
9fb355b
Comprehensive test print: all text styles, barcodes, 2D symbols, bit …
danielmeza Jun 6, 2026
a2d7484
Add Monitor window: ESC-POS-.NET client to exercise the emulator
danielmeza Jun 6, 2026
4723f18
Printer reacts to ready-state; richer monitor status indicators
danielmeza Jun 6, 2026
64cf58c
Gate line feed when not ready so blocked prints leave no blank receipts
danielmeza Jun 6, 2026
3a81f2a
Re-arm print-blocked notification per job so every blocked print noti…
danielmeza Jun 6, 2026
d69caf4
Treat warnings (incl. NuGet audit) as errors; fix all warnings; de-ma…
danielmeza Jun 6, 2026
77e3a4e
Toast stays longer (re-armable timer); move test responsibility to th…
danielmeza Jun 6, 2026
84d23d2
Showcase the Monitor window in the README with screenshots
danielmeza Jun 6, 2026
328590e
README: list ESC-POS-.NET (Monitor test client) in Built with
danielmeza Jun 6, 2026
a141911
Monitor can connect over serial as well as TCP
danielmeza Jun 6, 2026
7d8aefb
Monitor: add direct USB printing (libusb) as a third transport
danielmeza Jun 6, 2026
f527f5f
Fix 'Unable to load libusb-1.0' by resolving the native lib at runtime
danielmeza Jun 6, 2026
97e0594
Monitor: clear libusb-not-found log with install steps; copyable acti…
danielmeza Jun 6, 2026
a26eaa9
Fix libusb discovery: augment NATIVE_DLL_SEARCH_DIRECTORIES instead o…
danielmeza Jun 6, 2026
97d30ba
Monitor USB: bidirectional transport with status (UsbPrinter : BasePr…
danielmeza Jun 6, 2026
dc582ec
Fix app crash on USB disconnect; log unhandled exceptions; lock trans…
danielmeza Jun 6, 2026
1dbcdd5
Merge branch 'main' into fix/usb-disconnect-crash
danielmeza Jun 6, 2026
009f118
Merge pull request #7 from danielmeza/fix/usb-disconnect-crash
danielmeza Jun 6, 2026
59b6792
Refactor into layered packages with a swappable render layer
danielmeza Jun 21, 2026
04596cf
Accept raw byte[] / ReadOnlySpan<byte> ESC/POS input
danielmeza Jun 21, 2026
ad6f8f3
Merge pull request #8 from danielmeza/refactor/layered-packages
danielmeza Jun 21, 2026
4fdf8ef
Add package usage docs (docs/packages) with Mermaid diagrams
danielmeza Jun 21, 2026
25fc2ca
Add headless WASM JS-interop module (render ESC/POS to PNG from any JS)
danielmeza Jun 21, 2026
978b7da
Add TypeScript type definitions for the WASM JS wrapper
danielmeza Jun 21, 2026
c1a2942
Convert remaining value-dispatch switches to SmartEnum object models
danielmeza Jun 21, 2026
54ec2fa
Merge pull request #10 from danielmeza/refactor/smartenum-dispatch
danielmeza Jun 21, 2026
cd44872
Merge pull request #9 from danielmeza/feat/wasm-js-interop
danielmeza Jun 21, 2026
f4f91ab
Bump version to 1.1.0
danielmeza Jun 21, 2026
5991d24
Add a managed ImageSharp render backend (browser-safe, no native)
yhonc9 Jul 4, 2026
fd05c96
Publish NuGet packages to GasoleoTechnology via Trusted Publishing
danielmeza Jul 6, 2026
b6a7836
Add initial settings.json file with permissions structure
danielmeza Jul 6, 2026
4e35a84
Merge pull request #11 from yhonc9/feat/imagesharp-render-backend
danielmeza Jul 7, 2026
bd00d24
Merge pull request #12 from danielmeza/feat/nuget-trusted-publishing
danielmeza Jul 7, 2026
d5e667e
Match SkiaSharp advance width in ImageSharp text measurement
danielmeza Jul 7, 2026
9b81222
Select the render backend at runtime in the desktop app
danielmeza Jul 7, 2026
4a8e6c7
Add a Blazor web emulator sample; retire the JS-interop Wasm demo
danielmeza Jul 7, 2026
ed1045a
Bump version to 1.2.0
danielmeza Jul 7, 2026
b817825
Merge pull request #13 from danielmeza/release/v1.2.0
danielmeza Jul 7, 2026
1ed1884
Docs: add ImageSharp backend, Blazor web guide, and a render-backend …
danielmeza Jul 7, 2026
72d9a6f
Merge pull request #14 from danielmeza/docs/v1.2.0
danielmeza Jul 7, 2026
0ff1400
Unify apps (Phase 1): shared CrossEscPos.App + thin Desktop head
danielmeza Jul 7, 2026
ff5e4c9
Unify apps (Phases 2-4): Browser head on shared app, browser transpor…
danielmeza Jul 7, 2026
26036c2
Browser serial: add a WebUSB (CDC-ACM) fallback so serial works witho…
danielmeza Jul 7, 2026
d981cb4
Browser serial: configurable baud rate (parity with desktop + ESPWebT…
danielmeza Jul 7, 2026
64d00d6
Share the ConnectionsView: one uniform transport model across both heads
danielmeza Jul 7, 2026
b56f888
Share the Monitor over a single SignalR host; strongly-typed bridge
danielmeza Jul 7, 2026
44ce478
Let the browser choose the proxy's TCP listen address/port per session
danielmeza Jul 7, 2026
420c778
Docs: update README for the SignalR host; drop the dead WebSocket tra…
danielmeza Jul 7, 2026
2bffb39
Fix CI: make the host's WASM-client publish opt-in (was racing the so…
danielmeza Jul 7, 2026
1053e9e
Fix host serving 404: auto-populate wwwroot on a project/run build, s…
danielmeza Jul 7, 2026
93d7673
Give the browser Monitor the desktop's multi-transport UI (Serial / U…
danielmeza Jul 7, 2026
a64fae8
Fix browser PNG export: download via a JS blob instead of the File Sy…
danielmeza Jul 7, 2026
00fc2d8
Complete the browser Monitor: add a Network (TCP) mode dialed by the …
danielmeza Jul 7, 2026
a82cbc9
Auto-connect the browser TCP proxy on load (full desktop parity)
danielmeza Jul 7, 2026
754dbb2
Fix browser Monitor: enable Automatic Status Back so the status panel…
danielmeza Jul 7, 2026
8da2520
Lock connection fields while a transport is connected
danielmeza Jul 7, 2026
59da2d1
Merge pull request #16 from danielmeza/feat/unified-app
danielmeza Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"permissions": {
}
}
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches: [main, migrate-to-avalonia]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json

# The browser (WASM) head needs the wasm-tools workload to build.
- name: Install wasm-tools workload
run: dotnet workload install wasm-tools

- name: Restore
run: dotnet restore CrossEscPos.slnx

- name: Build
run: dotnet build CrossEscPos.slnx -c Release --no-restore

- name: Test
run: dotnet test CrossEscPos.slnx -c Release --no-build

- name: Pack libraries
run: dotnet pack CrossEscPos.slnx -c Release --no-build -o artifacts/packages

- uses: actions/upload-artifact@v4
with:
name: nupkg
path: artifacts/packages/*.nupkg
if-no-files-found: warn
166 changes: 166 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
name: Release

# Builds self-contained desktop apps for Windows, Linux and macOS, packs the NuGet libraries, and
# publishes everything to a GitHub Release. Trigger by pushing a tag like `v1.2.3`, or run manually
# (workflow_dispatch) to just build artifacts.

on:
push:
tags: ['v*']
workflow_dispatch:

permissions:
contents: write

jobs:
build:
name: Build ${{ matrix.rid }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { rid: win-x64, os: ubuntu-latest, kind: zip }
- { rid: linux-x64, os: ubuntu-latest, kind: targz }
- { rid: osx-x64, os: macos-latest, kind: app }
- { rid: osx-arm64, os: macos-latest, kind: app }
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json

- name: Determine version
id: ver
shell: bash
run: |
VER=1.0.0
if [ "$GITHUB_REF_TYPE" = "tag" ]; then VER="${GITHUB_REF_NAME#v}"; fi
echo "version=$VER" >> "$GITHUB_OUTPUT"

- name: Publish (self-contained)
run: >
dotnet publish src/CrossEscPos.App.Desktop/CrossEscPos.App.Desktop.csproj
-c Release
-r ${{ matrix.rid }}
--self-contained true
-p:PublishSingleFile=false
-p:Version=${{ steps.ver.outputs.version }}
-o publish/${{ matrix.rid }}

- name: Package — zip (Windows)
if: matrix.kind == 'zip'
run: |
cd publish/${{ matrix.rid }}
zip -r ../../CrossEscPos-${{ matrix.rid }}.zip .

- name: Package — tar.gz (Linux)
if: matrix.kind == 'targz'
run: tar -czf CrossEscPos-${{ matrix.rid }}.tar.gz -C publish/${{ matrix.rid }} .

- name: Package — .app bundle (macOS)
if: matrix.kind == 'app'
run: |
chmod +x scripts/make-macos-app.sh
scripts/make-macos-app.sh publish/${{ matrix.rid }} dist "${{ steps.ver.outputs.version }}"
ditto -c -k --keepParent dist/CrossEscPos.app CrossEscPos-${{ matrix.rid }}.zip

- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.rid }}
path: |
CrossEscPos-${{ matrix.rid }}.zip
CrossEscPos-${{ matrix.rid }}.tar.gz
if-no-files-found: ignore

pack:
name: Pack NuGet libraries
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json

- name: Determine version
id: ver
shell: bash
run: |
VER=1.0.0
if [ "$GITHUB_REF_TYPE" = "tag" ]; then VER="${GITHUB_REF_NAME#v}"; fi
echo "version=$VER" >> "$GITHUB_OUTPUT"

# The packable libraries don't need the browser head, so pack each individually (no wasm workload).
- name: Pack
shell: bash
run: |
for proj in Abstractions Core Rendering.Skia Rendering.ImageSharp Transports Controls; do
dotnet pack "src/CrossEscPos.$proj/CrossEscPos.$proj.csproj" \
-c Release -p:Version=${{ steps.ver.outputs.version }} -o packages
done

- uses: actions/upload-artifact@v4
with:
name: nupkg
path: |
packages/*.nupkg
packages/*.snupkg

publish-nuget:
name: Publish to NuGet.org
needs: pack
runs-on: ubuntu-latest
# Only publish for real version tags (v*), never on a manual workflow_dispatch dry run.
if: startsWith(github.ref, 'refs/tags/')
# Scopes the OIDC token to this environment; also lets you add a manual approval gate in
# Settings → Environments → release before anything reaches nuget.org.
environment: release
permissions:
id-token: write # required: mints the GitHub OIDC token for NuGet Trusted Publishing
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json

- uses: actions/download-artifact@v4
with:
name: nupkg
path: packages

# Exchanges the GitHub OIDC token for a short-lived (1 h) nuget.org API key. No stored key.
# NUGET_USER is your nuget.org profile name (NOT your email); set it as a repo/environment secret.
- name: NuGet login (OIDC → short-lived API key)
id: login
uses: NuGet/login@v1
with:
user: ${{ secrets.NUGET_USER }}

# Pushing *.nupkg also pushes each matching *.snupkg symbol package automatically.
- name: Push packages
run: >
dotnet nuget push "packages/*.nupkg"
--api-key ${{ steps.login.outputs.NUGET_API_KEY }}
--source https://api.nuget.org/v3/index.json
--skip-duplicate

release:
name: Create GitHub Release
needs: [build, pack]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/download-artifact@v4
with:
path: artifacts

- name: List artifacts
run: find artifacts -type f

- uses: softprops/action-gh-release@v2
with:
files: artifacts/**/*
generate_release_notes: true
fail_on_unmatched_files: false
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,14 @@ riderModule.iml
/_ReSharper.Caches/
/.vs
/.idea/

# Runtime debug dumps written by ReceiptPrinter.FeedEscPos
last_escpos_receive.txt
last_ticket.bin
last_*.txt

# macOS
.DS_Store

# Generated: the host publishes the Avalonia WASM client here on first build.
samples/CrossEscPos.Host/wwwroot/
10 changes: 0 additions & 10 deletions App.xaml

This file was deleted.

25 changes: 0 additions & 25 deletions App.xaml.cs

This file was deleted.

10 changes: 0 additions & 10 deletions AssemblyInfo.cs

This file was deleted.

23 changes: 23 additions & 0 deletions CrossEscPos.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Solution>
<Folder Name="/samples/">
<Project Path="samples/CrossEscPos.Headless/CrossEscPos.Headless.csproj" />
<Project Path="samples/CrossEscPos.Host/CrossEscPos.Host.csproj" />
</Folder>
<Folder Name="/src/">
<Project Path="src/CrossEscPos.Abstractions/CrossEscPos.Abstractions.csproj" />
<Project Path="src/CrossEscPos.Bridge/CrossEscPos.Bridge.csproj" />
<Project Path="src/CrossEscPos.App/CrossEscPos.App.csproj" />
<Project Path="src/CrossEscPos.App.Browser/CrossEscPos.App.Browser.csproj" />
<Project Path="src/CrossEscPos.App.Desktop/CrossEscPos.App.Desktop.csproj" />
<Project Path="src/CrossEscPos.Controls/CrossEscPos.Controls.csproj" />
<Project Path="src/CrossEscPos.Core/CrossEscPos.Core.csproj" />
<Project Path="src/CrossEscPos.Rendering.ImageSharp/CrossEscPos.Rendering.ImageSharp.csproj" />
<Project Path="src/CrossEscPos.Rendering.Skia/CrossEscPos.Rendering.Skia.csproj" />
<Project Path="src/CrossEscPos.Transports/CrossEscPos.Transports.csproj" />
<Project Path="src/CrossEscPos.Transports.Browser/CrossEscPos.Transports.Browser.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/CrossEscPos.Controls.Tests/CrossEscPos.Controls.Tests.csproj" />
<Project Path="tests/CrossEscPos.Core.Tests/CrossEscPos.Core.Tests.csproj" />
</Folder>
</Solution>
46 changes: 46 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<Project>

<!-- Shared build settings for every project in the repository. Individual projects override the
target framework (e.g. the desktop WinExe, the net10.0-browser WASM app) as needed. -->
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<!-- One shared root namespace across every assembly, so types resolve by feature/directory
(e.g. CrossEscPos.Emulator, CrossEscPos.Graphics) regardless of which package they live in. -->
<RootNamespace>CrossEscPos</RootNamespace>
<!-- The codebase uses explicit usings; keep implicit usings off to match. -->
<ImplicitUsings>disable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- Security-audit findings (vulnerable packages) must fail the build/CI, not just warn. -->
<NuGetAuditMode>all</NuGetAuditMode>
<!-- Libraries opt into packaging individually; apps and samples stay false. -->
<IsPackable>false</IsPackable>
</PropertyGroup>

<!-- NuGet package metadata, applied to the projects that set IsPackable=true. -->
<PropertyGroup>
<Version>1.2.0</Version>
<Authors>Daniel Meza</Authors>
<!-- Packages are published to the Gasoleo Technology organization on nuget.org. -->
<Company>Gasoleo Technology</Company>
<Product>CrossEscPos</Product>
<Copyright>Copyright (c) 2026 Daniel Meza / Gasoleo Technology</Copyright>
<PackageProjectUrl>https://github.com/danielmeza/CrossEscPosEmulator</PackageProjectUrl>
<RepositoryUrl>https://github.com/danielmeza/CrossEscPosEmulator</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>escpos;receipt;printer;emulator;thermal;pos</PackageTags>
<!-- SPDX license expression; the LICENSE file at the repo root is packed via Directory.Build.targets. -->
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<!-- Source Link: embed repo/commit info and untracked sources so consumers can step into the code.
The GitHub Source Link provider ships in the .NET SDK, so no extra package reference is needed. -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- Deterministic, CI-stamped builds when running on GitHub Actions. -->
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>

</Project>
11 changes: 11 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project>

<!-- Runs AFTER each project's own PropertyGroup, so $(IsPackable) reflects the per-project override
(Directory.Build.props imports first, when IsPackable is still the default false). Packs the shared
README into the root of every packable NuGet package to satisfy <PackageReadmeFile>. The LICENSE is
declared via <PackageLicenseExpression> (SPDX), which needs no packed file. -->
<ItemGroup Condition="'$(IsPackable)' == 'true'">
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" Visible="false" />
</ItemGroup>

</Project>
9 changes: 0 additions & 9 deletions Emulator/Abstraction/IReceiptPrintable.cs

This file was deleted.

Loading