tscLabelBuilder.ts
3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* TSC 标签指令构建(纯 TypeScript,无 require/import 外部 CJS 模块)
* 使用 UTF-8 编码。对于纯英文/ASCII 内容,UTF-8 与 GB18030 字节一致,佳博打印机可正常打印。
* 若需中文等非 ASCII,可考虑运行时动态加载 tsc.js(仅 APP 端)。
*/
/** 将字符串转为 UTF-8 字节数组(不依赖 TextEncoder) */
function stringToUtf8Bytes (str: string): number[] {
const out: number[] = []
for (let i = 0; i < str.length; i++) {
let c = str.charCodeAt(i)
if (c < 0x80) {
out.push(c)
} else if (c < 0x800) {
out.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f))
} else if (c < 0xd800 || c >= 0xe000) {
out.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f))
} else {
i++
const c2 = str.charCodeAt(i)
const u = ((c & 0x3ff) << 10) + (c2 & 0x3ff) + 0x10000
out.push(
0xf0 | (u >> 18),
0x80 | ((u >> 12) & 0x3f),
0x80 | ((u >> 6) & 0x3f),
0x80 | (u & 0x3f)
)
}
}
return out
}
function addCommandBytes (out: number[], str: string) {
const bytes = stringToUtf8Bytes(str)
for (let i = 0; i < bytes.length; i++) out.push(bytes[i])
}
function escapeTscString (s: string): string {
return String(s).replace(/\\/g, '\\\\').replace(/"/g, '\\"')
}
/**
* 构建标签打印指令字节数组(TSC)
* 与官方 Demo createLabel 格式一致(SIZE 100x30, GAP 0)
*/
export function buildTscLabel (options: {
productName: string
labelId: string
printQty?: number
widthMm?: number
heightMm?: number
category?: string
extraLine?: string
}): number[] {
const {
productName,
labelId,
printQty = 1,
widthMm = 100,
heightMm = 30,
category = '',
extraLine = '',
} = options
const out: number[] = []
const add = (s: string) => addCommandBytes(out, s + '\r\n')
let y = 10
add(`SIZE ${widthMm} mm,${heightMm} mm`)
add('GAP 0 mm,0 mm')
add('CLS')
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"${escapeTscString(productName)}"`)
y += 35
if (category) {
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Category: ${escapeTscString(category)}"`)
y += 35
}
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"ID: ${escapeTscString(labelId)}"`)
y += 35
if (extraLine) {
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"${escapeTscString(extraLine)}"`)
y += 35
}
add(`QRCODE 50,${y},L,5,A,0,"${escapeTscString(labelId)}"`)
add(`PRINT 1,${printQty}`)
add('FEED 1')
return out
}
/**
* 食品营养成分标签测试打印(Nutrition Facts 格式)
*/
export function buildTestTscLabel (): number[] {
const out: number[] = []
const add = (s: string) => addCommandBytes(out, s + '\r\n')
let y = 10
add('SIZE 100 mm,70 mm')
add('GAP 0 mm,0 mm')
add('CLS')
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"NUTRITION FACTS"`)
y += 28
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Grilled Chicken Breast"`)
y += 28
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Serving Size 1 piece (100g)"`)
y += 32
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Calories 165"`)
y += 28
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Total Fat 4g"`)
y += 24
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Saturated Fat 1g"`)
y += 24
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Cholesterol 85mg"`)
y += 24
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Sodium 75mg"`)
y += 24
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Total Carb 0g"`)
y += 24
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Protein 31g"`)
y += 28
add(`TEXT 50,${y},"TSS24.BF2",0,1,1,"Exp: 01/17/25 ID: TEST-251227"`)
y += 35
add(`QRCODE 50,${y},L,4,A,0,"TEST-251227-001"`)
add('PRINT 1,1')
add('FEED 1')
return out
}