thermal 0.2.0 β 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +12 -14
- data/lib/thermal/db/device.rb +80 -79
- data/lib/thermal/escpos/buffer.rb +167 -167
- data/lib/thermal/profile.rb +71 -71
- data/lib/thermal/stargraphic/writer.rb +10 -1
- data/lib/thermal/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ec2f32edf56df60bcab0eccadcbfdb990423a1e1ea821794b6e28918c000c4df
|
|
4
|
+
data.tar.gz: 45dc3e615b71ad3534f9bca88f3104d01cbc92f95daf668366261e5e9abdeb71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12d99782797190f588a656f5f0aef5025aae281eaf555381c105ac50d189ac2932dafbfc09123458beaaa262342689bb52840c02dda843c4da1aeb447c86c310
|
|
7
|
+
data.tar.gz: fdfd15fe4144c92065651bc5758af19386d5a134e56392eb0c880dc73458d46769ab8db97a97e1a9c02fb0852a08c04fde97f31a4766afd3140e63e42bd95f74
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Thermal printer support for Ruby. Used to print receipts, chits, tickets, labels, etc.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/rb/thermal)
|
|
6
|
-
[](https://github.com/tablecheck/thermal/actions/workflows/test.yml)
|
|
7
7
|
[](https://github.com/rubocop/rubocop)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
|
|
@@ -167,14 +167,11 @@ To add support for additional Thermal printers.
|
|
|
167
167
|
- Add new code in `lib/thermal/printer/escpos.rb`
|
|
168
168
|
- Add new code in `lib/thermal/printer/starprnt.rb`
|
|
169
169
|
|
|
170
|
-
#
|
|
170
|
+
# π Third-Party Documentation
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
See the [tablecheck/thermal-docs](https://github.com/tablecheck/thermal-docs) repo.
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
based in Tokyo, Japan. πΌ We use Thermal to help our restaurant users print chits, receipts, and
|
|
176
|
-
QR codes to serve their guests' reservations. If you are seeking your next career adventure,
|
|
177
|
-
[we're hiring](https://careers.tablecheck.com/)!
|
|
174
|
+
# π Acknowledgements
|
|
178
175
|
|
|
179
176
|
### π Data Sources
|
|
180
177
|
|
|
@@ -184,17 +181,18 @@ to provide a comprehensive list of thermal printers.
|
|
|
184
181
|
|
|
185
182
|
### π Special Thanks
|
|
186
183
|
|
|
187
|
-
This gem draws inspiration from the following libraries.
|
|
188
|
-
Thank you to the authors for their hard work.
|
|
184
|
+
This gem draws inspiration from the following libraries. Thank you to the authors for their hard work.
|
|
189
185
|
- [escpos-php](https://github.com/escpos/escpos-php)
|
|
190
186
|
- [escpos-printer-db](https://github.com/receipt-print-hq/escpos-printer-db)
|
|
191
187
|
- [EscPosEncoder JS](https://github.com/NielsLeenheer/EscPosEncoder/blob/master/src/esc-pos-encoder.js)
|
|
192
188
|
|
|
193
|
-
###
|
|
189
|
+
### π¨βπ» Maintainers
|
|
194
190
|
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
Thermal is maintained and battle-tested by the team at [TableCheck](https://www.tablecheck.com)
|
|
192
|
+
based in Tokyo, Japan. πΌ We use Thermal to help our restaurant users print chits, receipts, and
|
|
193
|
+
QR codes to serve their guests' reservations. If you are seeking your next career adventure,
|
|
194
|
+
[we're hiring](https://careers.tablecheck.com/)!
|
|
197
195
|
|
|
198
|
-
|
|
196
|
+
# π License
|
|
199
197
|
|
|
200
|
-
This gem is released under the MIT License. Please see the [LICENSE](LICENSE) file for details.
|
|
198
|
+
This gem is released under the MIT License. Please see the [LICENSE](LICENSE) file for details.
|
data/lib/thermal/db/device.rb
CHANGED
|
@@ -1,79 +1,80 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Thermal
|
|
4
|
-
module Db
|
|
5
|
-
class Device
|
|
6
|
-
DEFAULT_COL_WIDTH = 42
|
|
7
|
-
|
|
8
|
-
attr_reader :key
|
|
9
|
-
|
|
10
|
-
def initialize(key, data)
|
|
11
|
-
@key = key
|
|
12
|
-
@data = data
|
|
13
|
-
|
|
14
|
-
# eager load cache
|
|
15
|
-
codepage_index
|
|
16
|
-
charset_index
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def name
|
|
20
|
-
@data['name']&.to_s
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def format
|
|
24
|
-
@data['format']&.to_s
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def supports?(feature)
|
|
28
|
-
!!@data.dig('features', feature)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# TODO: this needs to be dynamic in the printer
|
|
32
|
-
def col_width
|
|
33
|
-
@col_width ||= @data.dig('fonts', 0, 'columns') || DEFAULT_COL_WIDTH
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def find_encoding(u_codepoint)
|
|
37
|
-
if (codepage = codepage_index[u_codepoint])
|
|
38
|
-
[:codepage, codepage].freeze
|
|
39
|
-
elsif (charset = charset_index[u_codepoint]) && charset > 0
|
|
40
|
-
[:charset, charset].freeze
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# def find_codepage(encoding)
|
|
45
|
-
# encoding = encoding&.to_s
|
|
46
|
-
# device.codepages&.invert&.[](encoding) || 0
|
|
47
|
-
# end
|
|
48
|
-
|
|
49
|
-
def codepages
|
|
50
|
-
@codepages ||= begin
|
|
51
|
-
codepages = @data['codepages'] || ::Thermal::Db::DEFAULT_CODEPAGES
|
|
52
|
-
codepages.each_with_object({}) do |(k, v), h|
|
|
53
|
-
encoding = ::Thermal::Db.encoding(v)
|
|
54
|
-
h[k] = encoding if encoding
|
|
55
|
-
end.freeze
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def charsets
|
|
60
|
-
@charsets ||= begin
|
|
61
|
-
charsets = @data['charsets'] || ::Thermal::Db::DEFAULT_CHARSETS
|
|
62
|
-
::Thermal::Util.index_with(charsets) { |i| ::Thermal::Db.charset(i) }.freeze
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
private
|
|
67
|
-
|
|
68
|
-
def codepage_index
|
|
69
|
-
@codepage_index ||= codepages.map { |k, v| ::Thermal::Util.index_with(v.u_codepoints, k) }
|
|
70
|
-
.reverse.inject(&:merge).freeze
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def charset_index
|
|
74
|
-
@charset_index ||= charsets.values
|
|
75
|
-
.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Thermal
|
|
4
|
+
module Db
|
|
5
|
+
class Device
|
|
6
|
+
DEFAULT_COL_WIDTH = 42
|
|
7
|
+
|
|
8
|
+
attr_reader :key
|
|
9
|
+
|
|
10
|
+
def initialize(key, data)
|
|
11
|
+
@key = key
|
|
12
|
+
@data = data
|
|
13
|
+
|
|
14
|
+
# eager load cache
|
|
15
|
+
codepage_index
|
|
16
|
+
charset_index
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def name
|
|
20
|
+
@data['name']&.to_s
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def format
|
|
24
|
+
@data['format']&.to_s
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def supports?(feature)
|
|
28
|
+
!!@data.dig('features', feature)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# TODO: this needs to be dynamic in the printer
|
|
32
|
+
def col_width
|
|
33
|
+
@col_width ||= @data.dig('fonts', 0, 'columns') || DEFAULT_COL_WIDTH
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def find_encoding(u_codepoint)
|
|
37
|
+
if (codepage = codepage_index[u_codepoint])
|
|
38
|
+
[:codepage, codepage].freeze
|
|
39
|
+
elsif (charset = charset_index[u_codepoint]) && charset > 0
|
|
40
|
+
[:charset, charset].freeze
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# def find_codepage(encoding)
|
|
45
|
+
# encoding = encoding&.to_s
|
|
46
|
+
# device.codepages&.invert&.[](encoding) || 0
|
|
47
|
+
# end
|
|
48
|
+
|
|
49
|
+
def codepages
|
|
50
|
+
@codepages ||= begin
|
|
51
|
+
codepages = @data['codepages'] || ::Thermal::Db::DEFAULT_CODEPAGES
|
|
52
|
+
codepages.each_with_object({}) do |(k, v), h|
|
|
53
|
+
encoding = ::Thermal::Db.encoding(v)
|
|
54
|
+
h[k] = encoding if encoding
|
|
55
|
+
end.freeze
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def charsets
|
|
60
|
+
@charsets ||= begin
|
|
61
|
+
charsets = @data['charsets'] || ::Thermal::Db::DEFAULT_CHARSETS
|
|
62
|
+
::Thermal::Util.index_with(charsets) { |i| ::Thermal::Db.charset(i) }.freeze
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def codepage_index
|
|
69
|
+
@codepage_index ||= codepages.map { |k, v| ::Thermal::Util.index_with(v.u_codepoints, k) }
|
|
70
|
+
.reverse.inject(&:merge).freeze
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def charset_index
|
|
74
|
+
@charset_index ||= charsets.values
|
|
75
|
+
.map! { |c| ::Thermal::Util.index_with(c.u_codepoints, c.key) }
|
|
76
|
+
.reverse.inject(&:merge).freeze
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Thermal
|
|
4
|
-
module Escpos
|
|
5
|
-
# Inspired by mike42/escpos-php
|
|
6
|
-
# https://github.com/mike42/escpos-php/blob/development/src/Mike42/Escpos/PrintBuffers/EscposPrintBuffer.php
|
|
7
|
-
class Buffer < ::Thermal::ByteBuffer
|
|
8
|
-
extend Forwardable
|
|
9
|
-
|
|
10
|
-
def initialize(profile)
|
|
11
|
-
super()
|
|
12
|
-
@profile = profile
|
|
13
|
-
@codepage = 0
|
|
14
|
-
@charset = 0
|
|
15
|
-
@cjk = false
|
|
16
|
-
init_buffer!
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def_delegators :@profile,
|
|
20
|
-
:find_encoding,
|
|
21
|
-
:cjk_encoding,
|
|
22
|
-
:codepages,
|
|
23
|
-
:charsets,
|
|
24
|
-
:codepoint_cjk_skip?,
|
|
25
|
-
:codepoint_cjk_force?
|
|
26
|
-
|
|
27
|
-
def current_encoding
|
|
28
|
-
@cjk ? cjk_encoding : codepages[@codepage]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def current_charset
|
|
32
|
-
charsets[@charset]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def write_text(text, replace: nil, no_cjk: false)
|
|
36
|
-
text = ::Thermal::Util.normalize_utf8(text, replace: replace)
|
|
37
|
-
text&.each_codepoint do |u_codepoint|
|
|
38
|
-
write_u_codepoint(u_codepoint, replace: replace, no_cjk: no_cjk)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
private
|
|
43
|
-
|
|
44
|
-
def write_u_codepoint(u_codepoint, replace: nil, no_cjk: false, fallback: false)
|
|
45
|
-
replace ||= ::Thermal.replace_char
|
|
46
|
-
|
|
47
|
-
if ascii?(u_codepoint)
|
|
48
|
-
reset_charset!(u_codepoint)
|
|
49
|
-
write(u_codepoint)
|
|
50
|
-
elsif current_encoding &&
|
|
51
|
-
(!@cjk || (!no_cjk && !codepoint_cjk_skip?(u_codepoint))) &&
|
|
52
|
-
(@cjk || !codepoint_cjk_force?(u_codepoint)) &&
|
|
53
|
-
(codepoint = current_encoding.codepoint(u_codepoint))
|
|
54
|
-
write(codepoint)
|
|
55
|
-
else
|
|
56
|
-
location, value = find_encoding(u_codepoint, no_cjk: no_cjk)
|
|
57
|
-
case location
|
|
58
|
-
when :codepage
|
|
59
|
-
set_codepage(value)
|
|
60
|
-
codepoint = current_encoding.codepoint(u_codepoint)
|
|
61
|
-
# TODO: move this to encoding class
|
|
62
|
-
raise_missing_codepoint!(u_codepoint, current_encoding) unless codepoint
|
|
63
|
-
write(codepoint)
|
|
64
|
-
when :charset
|
|
65
|
-
set_charset(value)
|
|
66
|
-
codepoint = current_charset.codepoint(u_codepoint)
|
|
67
|
-
# TODO: move this to encoding class
|
|
68
|
-
raise_missing_codepoint!(u_codepoint, current_encoding) unless codepoint
|
|
69
|
-
write(codepoint)
|
|
70
|
-
when :cjk
|
|
71
|
-
set_cjk(true)
|
|
72
|
-
char = current_encoding.codepoint(u_codepoint)
|
|
73
|
-
# TODO: move this to encoding class
|
|
74
|
-
raise_missing_codepoint!(u_codepoint, current_encoding) unless char
|
|
75
|
-
write(char)
|
|
76
|
-
else
|
|
77
|
-
write_u_codepoint(replace.ord, replace: ' ', fallback: true) unless fallback || replace.empty?
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def init_buffer!
|
|
83
|
-
sequence(::Escpos::HW_INIT)
|
|
84
|
-
|
|
85
|
-
# CJK is on after HW_INIT for Chinese models.
|
|
86
|
-
# To ensure consistency, we explicitly set it off.
|
|
87
|
-
# https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=175
|
|
88
|
-
sequence(Cmd::SET_CJK_OFF) if cjk_supported?
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def ascii?(codepoint, extended: false)
|
|
92
|
-
(codepoint == 10) ||
|
|
93
|
-
(
|
|
94
|
-
(extended && codepoint
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def set_charset(charset) # rubocop:disable Naming/AccessorMethodName
|
|
98
|
-
return if @charset == charset
|
|
99
|
-
|
|
100
|
-
sequence([0x1b, 0x52] + [charset])
|
|
101
|
-
@charset = charset
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def reset_charset!(u_codepoint)
|
|
105
|
-
return unless ::Thermal::Db::Charset::CODEPOINTS.include?(u_codepoint)
|
|
106
|
-
|
|
107
|
-
set_charset(0)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def set_codepage(codepage) # rubocop:disable Naming/AccessorMethodName
|
|
111
|
-
set_cjk(false)
|
|
112
|
-
return if @codepage == codepage
|
|
113
|
-
|
|
114
|
-
sequence(::Escpos::CP_SET + [codepage])
|
|
115
|
-
@codepage = codepage
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def set_cjk(enabled) # rubocop:disable Naming/AccessorMethodName
|
|
119
|
-
enabled ? set_cjk_on : set_cjk_off
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def set_cjk_on
|
|
123
|
-
return if !cjk_supported? || @cjk
|
|
124
|
-
|
|
125
|
-
sequence(cjk_on_command)
|
|
126
|
-
@cjk = true
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def set_cjk_off
|
|
130
|
-
return if !cjk_supported? || !@cjk
|
|
131
|
-
|
|
132
|
-
sequence(cjk_off_command)
|
|
133
|
-
@cjk = false
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def cjk_supported?
|
|
137
|
-
!!cjk_encoding
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def shift_jis?
|
|
141
|
-
cjk_encoding&.ruby == 'Shift_JIS'
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def cjk_on_command
|
|
145
|
-
if shift_jis?
|
|
146
|
-
Cmd::SET_JIS_MODE + [1]
|
|
147
|
-
else
|
|
148
|
-
Cmd::SET_CJK_ON
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def cjk_off_command
|
|
153
|
-
if shift_jis?
|
|
154
|
-
Cmd::SET_JIS_MODE + [0]
|
|
155
|
-
else
|
|
156
|
-
Cmd::SET_CJK_OFF
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# TODO: move this to encoding
|
|
161
|
-
def raise_missing_codepoint!(u_codepoint, encoding)
|
|
162
|
-
klass = encoding.class.name.split('::').last
|
|
163
|
-
raise "Codepoint U#{u_codepoint.to_s(16)} not found in #{klass} #{encoding.name}"
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Thermal
|
|
4
|
+
module Escpos
|
|
5
|
+
# Inspired by mike42/escpos-php
|
|
6
|
+
# https://github.com/mike42/escpos-php/blob/development/src/Mike42/Escpos/PrintBuffers/EscposPrintBuffer.php
|
|
7
|
+
class Buffer < ::Thermal::ByteBuffer
|
|
8
|
+
extend Forwardable
|
|
9
|
+
|
|
10
|
+
def initialize(profile)
|
|
11
|
+
super()
|
|
12
|
+
@profile = profile
|
|
13
|
+
@codepage = 0
|
|
14
|
+
@charset = 0
|
|
15
|
+
@cjk = false
|
|
16
|
+
init_buffer!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def_delegators :@profile,
|
|
20
|
+
:find_encoding,
|
|
21
|
+
:cjk_encoding,
|
|
22
|
+
:codepages,
|
|
23
|
+
:charsets,
|
|
24
|
+
:codepoint_cjk_skip?,
|
|
25
|
+
:codepoint_cjk_force?
|
|
26
|
+
|
|
27
|
+
def current_encoding
|
|
28
|
+
@cjk ? cjk_encoding : codepages[@codepage]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def current_charset
|
|
32
|
+
charsets[@charset]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def write_text(text, replace: nil, no_cjk: false)
|
|
36
|
+
text = ::Thermal::Util.normalize_utf8(text, replace: replace)
|
|
37
|
+
text&.each_codepoint do |u_codepoint|
|
|
38
|
+
write_u_codepoint(u_codepoint, replace: replace, no_cjk: no_cjk)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def write_u_codepoint(u_codepoint, replace: nil, no_cjk: false, fallback: false)
|
|
45
|
+
replace ||= ::Thermal.replace_char
|
|
46
|
+
|
|
47
|
+
if ascii?(u_codepoint)
|
|
48
|
+
reset_charset!(u_codepoint)
|
|
49
|
+
write(u_codepoint)
|
|
50
|
+
elsif current_encoding &&
|
|
51
|
+
(!@cjk || (!no_cjk && !codepoint_cjk_skip?(u_codepoint))) &&
|
|
52
|
+
(@cjk || !codepoint_cjk_force?(u_codepoint)) &&
|
|
53
|
+
(codepoint = current_encoding.codepoint(u_codepoint))
|
|
54
|
+
write(codepoint)
|
|
55
|
+
else
|
|
56
|
+
location, value = find_encoding(u_codepoint, no_cjk: no_cjk)
|
|
57
|
+
case location
|
|
58
|
+
when :codepage
|
|
59
|
+
set_codepage(value)
|
|
60
|
+
codepoint = current_encoding.codepoint(u_codepoint)
|
|
61
|
+
# TODO: move this to encoding class
|
|
62
|
+
raise_missing_codepoint!(u_codepoint, current_encoding) unless codepoint
|
|
63
|
+
write(codepoint)
|
|
64
|
+
when :charset
|
|
65
|
+
set_charset(value)
|
|
66
|
+
codepoint = current_charset.codepoint(u_codepoint)
|
|
67
|
+
# TODO: move this to encoding class
|
|
68
|
+
raise_missing_codepoint!(u_codepoint, current_encoding) unless codepoint
|
|
69
|
+
write(codepoint)
|
|
70
|
+
when :cjk
|
|
71
|
+
set_cjk(true)
|
|
72
|
+
char = current_encoding.codepoint(u_codepoint)
|
|
73
|
+
# TODO: move this to encoding class
|
|
74
|
+
raise_missing_codepoint!(u_codepoint, current_encoding) unless char
|
|
75
|
+
write(char)
|
|
76
|
+
else
|
|
77
|
+
write_u_codepoint(replace.ord, replace: ' ', fallback: true) unless fallback || replace.empty?
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def init_buffer!
|
|
83
|
+
sequence(::Escpos::HW_INIT)
|
|
84
|
+
|
|
85
|
+
# CJK is on after HW_INIT for Chinese models.
|
|
86
|
+
# To ensure consistency, we explicitly set it off.
|
|
87
|
+
# https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=175
|
|
88
|
+
sequence(Cmd::SET_CJK_OFF) if cjk_supported?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def ascii?(codepoint, extended: false)
|
|
92
|
+
(codepoint == 10) ||
|
|
93
|
+
codepoint.between?(32, 126) ||
|
|
94
|
+
(extended && codepoint.between?(128, 255))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def set_charset(charset) # rubocop:disable Naming/AccessorMethodName
|
|
98
|
+
return if @charset == charset
|
|
99
|
+
|
|
100
|
+
sequence([0x1b, 0x52] + [charset])
|
|
101
|
+
@charset = charset
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def reset_charset!(u_codepoint)
|
|
105
|
+
return unless ::Thermal::Db::Charset::CODEPOINTS.include?(u_codepoint)
|
|
106
|
+
|
|
107
|
+
set_charset(0)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def set_codepage(codepage) # rubocop:disable Naming/AccessorMethodName
|
|
111
|
+
set_cjk(false)
|
|
112
|
+
return if @codepage == codepage
|
|
113
|
+
|
|
114
|
+
sequence(::Escpos::CP_SET + [codepage])
|
|
115
|
+
@codepage = codepage
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def set_cjk(enabled) # rubocop:disable Naming/AccessorMethodName
|
|
119
|
+
enabled ? set_cjk_on : set_cjk_off
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def set_cjk_on
|
|
123
|
+
return if !cjk_supported? || @cjk
|
|
124
|
+
|
|
125
|
+
sequence(cjk_on_command)
|
|
126
|
+
@cjk = true
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def set_cjk_off
|
|
130
|
+
return if !cjk_supported? || !@cjk
|
|
131
|
+
|
|
132
|
+
sequence(cjk_off_command)
|
|
133
|
+
@cjk = false
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def cjk_supported?
|
|
137
|
+
!!cjk_encoding
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def shift_jis?
|
|
141
|
+
cjk_encoding&.ruby == 'Shift_JIS'
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def cjk_on_command
|
|
145
|
+
if shift_jis?
|
|
146
|
+
Cmd::SET_JIS_MODE + [1]
|
|
147
|
+
else
|
|
148
|
+
Cmd::SET_CJK_ON
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def cjk_off_command
|
|
153
|
+
if shift_jis?
|
|
154
|
+
Cmd::SET_JIS_MODE + [0]
|
|
155
|
+
else
|
|
156
|
+
Cmd::SET_CJK_OFF
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# TODO: move this to encoding
|
|
161
|
+
def raise_missing_codepoint!(u_codepoint, encoding)
|
|
162
|
+
klass = encoding.class.name.split('::').last
|
|
163
|
+
raise "Codepoint U#{u_codepoint.to_s(16)} not found in #{klass} #{encoding.name}"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
data/lib/thermal/profile.rb
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Thermal
|
|
4
|
-
class Profile
|
|
5
|
-
extend Forwardable
|
|
6
|
-
|
|
7
|
-
# TODO: some of these methods can be moved to an Escpos::Encoder class.
|
|
8
|
-
|
|
9
|
-
# These characters should always use codepage, even if present
|
|
10
|
-
# in CJK. HR chars have issues with double-printing in CJK encodings
|
|
11
|
-
# on Epson printers. This has been observed on Japanese (Shift-JIS)
|
|
12
|
-
# with \u2500 and Simplified Chinese (GB18030) with \u2584.
|
|
13
|
-
CODEPOINTS_CJK_SKIP = [
|
|
14
|
-
"\u2500".."\u259F", # box drawing + block elements
|
|
15
|
-
"\u2660".."\u2667" # card suits
|
|
16
|
-
].map(&:to_a).
|
|
17
|
-
|
|
18
|
-
# These characters exist in the Katakana codepage,
|
|
19
|
-
# but should use CJK encoding if available.
|
|
20
|
-
CODEPOINTS_CJK_FORCE = 'εεΉ΄ζζ₯ζεη§γεΈεΊηΊζδΊΊ'.each_codepoint.to_a.freeze
|
|
21
|
-
|
|
22
|
-
# Wraps a Device object with CJK encoding support.
|
|
23
|
-
def initialize(device, **opts)
|
|
24
|
-
@device_key = device.to_s
|
|
25
|
-
@cjk = ::Thermal::Db.find_cjk_encoding(opts[:cjk_encoding]) || opts[:cjk_encoding]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def device_name
|
|
29
|
-
device.name
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def cjk_encoding
|
|
33
|
-
return @cjk_encoding if defined?(@cjk_encoding)
|
|
34
|
-
|
|
35
|
-
@cjk_encoding = ::Thermal::Db.cjk_encoding(@cjk)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def_delegators :device,
|
|
39
|
-
:format,
|
|
40
|
-
:codepages,
|
|
41
|
-
:charsets,
|
|
42
|
-
:supports?,
|
|
43
|
-
:col_width
|
|
44
|
-
|
|
45
|
-
def find_encoding(u_codepoint, no_cjk: false)
|
|
46
|
-
device_encoding = device.find_encoding(u_codepoint)
|
|
47
|
-
if device_encoding && !codepoint_cjk_force?(u_codepoint)
|
|
48
|
-
device_encoding
|
|
49
|
-
elsif !no_cjk && cjk_encoding&.codepoint?(u_codepoint)
|
|
50
|
-
[:cjk, true].freeze
|
|
51
|
-
else # rubocop:disable Lint/DuplicateBranch
|
|
52
|
-
# codepoint_cjk_force failed
|
|
53
|
-
device_encoding
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def codepoint_cjk_skip?(u_codepoint)
|
|
58
|
-
CODEPOINTS_CJK_SKIP.include?(u_codepoint)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def codepoint_cjk_force?(u_codepoint)
|
|
62
|
-
CODEPOINTS_CJK_FORCE.include?(u_codepoint)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
private
|
|
66
|
-
|
|
67
|
-
def device
|
|
68
|
-
@device ||= ::Thermal::Db.device(@device_key)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Thermal
|
|
4
|
+
class Profile
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
7
|
+
# TODO: some of these methods can be moved to an Escpos::Encoder class.
|
|
8
|
+
|
|
9
|
+
# These characters should always use codepage, even if present
|
|
10
|
+
# in CJK. HR chars have issues with double-printing in CJK encodings
|
|
11
|
+
# on Epson printers. This has been observed on Japanese (Shift-JIS)
|
|
12
|
+
# with \u2500 and Simplified Chinese (GB18030) with \u2584.
|
|
13
|
+
CODEPOINTS_CJK_SKIP = [
|
|
14
|
+
"\u2500".."\u259F", # box drawing + block elements
|
|
15
|
+
"\u2660".."\u2667" # card suits
|
|
16
|
+
].map(&:to_a).join.each_codepoint.to_a.freeze
|
|
17
|
+
|
|
18
|
+
# These characters exist in the Katakana codepage,
|
|
19
|
+
# but should use CJK encoding if available.
|
|
20
|
+
CODEPOINTS_CJK_FORCE = 'εεΉ΄ζζ₯ζεη§γεΈεΊηΊζδΊΊ'.each_codepoint.to_a.freeze
|
|
21
|
+
|
|
22
|
+
# Wraps a Device object with CJK encoding support.
|
|
23
|
+
def initialize(device, **opts)
|
|
24
|
+
@device_key = device.to_s
|
|
25
|
+
@cjk = ::Thermal::Db.find_cjk_encoding(opts[:cjk_encoding]) || opts[:cjk_encoding]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def device_name
|
|
29
|
+
device.name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def cjk_encoding
|
|
33
|
+
return @cjk_encoding if defined?(@cjk_encoding)
|
|
34
|
+
|
|
35
|
+
@cjk_encoding = ::Thermal::Db.cjk_encoding(@cjk)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def_delegators :device,
|
|
39
|
+
:format,
|
|
40
|
+
:codepages,
|
|
41
|
+
:charsets,
|
|
42
|
+
:supports?,
|
|
43
|
+
:col_width
|
|
44
|
+
|
|
45
|
+
def find_encoding(u_codepoint, no_cjk: false)
|
|
46
|
+
device_encoding = device.find_encoding(u_codepoint)
|
|
47
|
+
if device_encoding && !codepoint_cjk_force?(u_codepoint)
|
|
48
|
+
device_encoding
|
|
49
|
+
elsif !no_cjk && cjk_encoding&.codepoint?(u_codepoint)
|
|
50
|
+
[:cjk, true].freeze
|
|
51
|
+
else # rubocop:disable Lint/DuplicateBranch
|
|
52
|
+
# codepoint_cjk_force failed
|
|
53
|
+
device_encoding
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def codepoint_cjk_skip?(u_codepoint)
|
|
58
|
+
CODEPOINTS_CJK_SKIP.include?(u_codepoint)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def codepoint_cjk_force?(u_codepoint)
|
|
62
|
+
CODEPOINTS_CJK_FORCE.include?(u_codepoint)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def device
|
|
68
|
+
@device ||= ::Thermal::Db.device(@device_key)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -216,8 +216,11 @@ module Stargraphic
|
|
|
216
216
|
def text_image(markup, width: @width, align: :left, font: 'Sans', delete: true)
|
|
217
217
|
tmp_path = ::Thermal.tmp_path("#{SecureRandom.uuid}.png")
|
|
218
218
|
|
|
219
|
+
# TODO: Fix font loading
|
|
220
|
+
# font ||= self.class.font
|
|
221
|
+
|
|
219
222
|
begin
|
|
220
|
-
|
|
223
|
+
configure = proc do |i|
|
|
221
224
|
i << '+antialias'
|
|
222
225
|
i << '+dither'
|
|
223
226
|
i.size width
|
|
@@ -232,6 +235,12 @@ module Stargraphic
|
|
|
232
235
|
i.negate
|
|
233
236
|
i << tmp_path
|
|
234
237
|
end
|
|
238
|
+
|
|
239
|
+
if ::MiniMagick.respond_to?(:convert) # MiniMagick 5+
|
|
240
|
+
::MiniMagick.convert(&configure)
|
|
241
|
+
else
|
|
242
|
+
::MiniMagick::Tool::Convert.new(&configure)
|
|
243
|
+
end
|
|
235
244
|
rescue StandardError => e
|
|
236
245
|
Bugsnag.notify(e) do |r|
|
|
237
246
|
r.add_metadata('data',
|
data/lib/thermal/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: thermal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Johnny Shields
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: base64
|
|
@@ -93,7 +92,6 @@ homepage: https://github.com/tablecheck/thermal
|
|
|
93
92
|
licenses: []
|
|
94
93
|
metadata:
|
|
95
94
|
rubygems_mfa_required: 'true'
|
|
96
|
-
post_install_message:
|
|
97
95
|
rdoc_options: []
|
|
98
96
|
require_paths:
|
|
99
97
|
- lib
|
|
@@ -108,8 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
108
106
|
- !ruby/object:Gem::Version
|
|
109
107
|
version: '0'
|
|
110
108
|
requirements: []
|
|
111
|
-
rubygems_version:
|
|
112
|
-
signing_key:
|
|
109
|
+
rubygems_version: 4.0.4
|
|
113
110
|
specification_version: 4
|
|
114
111
|
summary: Thermal printer support for Ruby
|
|
115
112
|
test_files: []
|