Add Epson TM-T20II receipt printing (title/body/QR, no ESC/POS knowledge needed)
deploy / deploy (push) Successful in 8s

Custom ReceiptBuilder instead of the escpos gem -- its diacritics handling
needed the same manual UTF-8->CP852 encode call anyway, based on earlier
experiments in ~/test/epson/.
This commit is contained in:
randy committed 2026-09-13 10:42:52 +02:00
1 parent 5c06f725f0
commit afae57aff4
4 files changed
+154

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
# Minimal chainable ESC/POS builder for the Epson TM-T20II.
#
# Written instead of pulling in the `escpos` gem: the gem's diacritics
# handling needed the same manual UTF-8->CP852 `.encode` call anyway, and a
# couple of its helpers didn't behave as documented against this printer --
# fewer moving parts doing it directly.
class ReceiptBuilder
INIT = "\x1B\x40".freeze
CP852 = "\x1B\x74\x12".freeze # code page for Slovak diacritics
ALIGN_LEFT = "\x1B\x61\x00".freeze
ALIGN_CENT = "\x1B\x61\x01".freeze
ALIGN_RIGH = "\x1B\x61\x02".freeze
BOLD_ON = "\x1B\x45\x01".freeze
BOLD_OFF = "\x1B\x45\x00".freeze
UNDER_ON = "\x1B\x2D\x01".freeze
UNDER_OFF = "\x1B\x2D\x00".freeze
TXT_NORM = "\x1D\x21\x00".freeze
TXT_BIG = "\x1D\x21\x11".freeze # double height and width
TXT_HIGH = "\x1D\x21\x01".freeze # double height
TXT_WIDE = "\x1D\x21\x10".freeze # double width
CUT = "\x1D\x56\x00".freeze
def initialize
@buffer = "".b
init
end
def init
@buffer << INIT << CP852
self
end
def text(str)
@buffer << str.encode('CP852', invalid: :replace, undef: :replace, replace: '?')
self
end
def align(mode)
@buffer << case mode
when :center then ALIGN_CENT
when :right then ALIGN_RIGH
else ALIGN_LEFT
end
self
end
def bold(enable = true)
@buffer << (enable ? BOLD_ON : BOLD_OFF)
self
end
def underline(enable = true)
@buffer << (enable ? UNDER_ON : UNDER_OFF)
self
end
def size(mode)
@buffer << case mode
when :big then TXT_BIG
when :high then TXT_HIGH
when :wide then TXT_WIDE
else TXT_NORM
end
self
end
# Native ESC/POS QR code
def qr(data, size: 6)
qr_data = data.b
store_len = qr_data.bytesize + 3
@buffer << "\x1D\x28\x6B\x03\x00\x31\x43" << size.chr
@buffer << "\x1D\x28\x6B\x03\x00\x31\x45\x30" # error correction L
@buffer << "\x1D\x28\x6B" << [store_len % 256, store_len / 256].pack('CC') << "\x31\x50\x30" << qr_data
@buffer << "\x1D\x28\x6B\x03\x00\x31\x51\x30" # print
self
end
# Native ESC/POS EAN-13
def ean13(code)
@buffer << "\x1D\x6B\x02" << code.b << "\x00"
self
end
def feed(lines = 3)
@buffer << ("\n" * lines)
self
end
def cut
@buffer << CUT
self
end
def render
@buffer
end
def print!(device)
File.open(device, 'wb') { |f| f.write(@buffer) }
end
end