@thermal-label/brother-ql-core 0.0.1 → 0.3.0

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.
Files changed (68) hide show
  1. package/dist/__tests__/devices.test.js +16 -2
  2. package/dist/__tests__/devices.test.js.map +1 -1
  3. package/dist/__tests__/media.test.js +37 -6
  4. package/dist/__tests__/media.test.js.map +1 -1
  5. package/dist/__tests__/pack-bits.test.d.ts +2 -0
  6. package/dist/__tests__/pack-bits.test.d.ts.map +1 -0
  7. package/dist/__tests__/pack-bits.test.js +90 -0
  8. package/dist/__tests__/pack-bits.test.js.map +1 -0
  9. package/dist/__tests__/preview.test.d.ts +2 -0
  10. package/dist/__tests__/preview.test.d.ts.map +1 -0
  11. package/dist/__tests__/preview.test.js +41 -0
  12. package/dist/__tests__/preview.test.js.map +1 -0
  13. package/dist/__tests__/protocol.test.js +46 -1
  14. package/dist/__tests__/protocol.test.js.map +1 -1
  15. package/dist/__tests__/status.test.js +28 -22
  16. package/dist/__tests__/status.test.js.map +1 -1
  17. package/dist/devices.d.ts +40 -21
  18. package/dist/devices.d.ts.map +1 -1
  19. package/dist/devices.js +38 -20
  20. package/dist/devices.js.map +1 -1
  21. package/dist/index.d.ts +8 -4
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +5 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/media.d.ts +43 -4
  26. package/dist/media.d.ts.map +1 -1
  27. package/dist/media.js +92 -24
  28. package/dist/media.js.map +1 -1
  29. package/dist/orientation.d.ts +11 -0
  30. package/dist/orientation.d.ts.map +1 -0
  31. package/dist/orientation.js +10 -0
  32. package/dist/orientation.js.map +1 -0
  33. package/dist/pack-bits.d.ts +20 -0
  34. package/dist/pack-bits.d.ts.map +1 -0
  35. package/dist/pack-bits.js +61 -0
  36. package/dist/pack-bits.js.map +1 -0
  37. package/dist/preview.d.ts +13 -0
  38. package/dist/preview.d.ts.map +1 -0
  39. package/dist/preview.js +31 -0
  40. package/dist/preview.js.map +1 -0
  41. package/dist/protocol.d.ts +2 -2
  42. package/dist/protocol.d.ts.map +1 -1
  43. package/dist/protocol.js +14 -8
  44. package/dist/protocol.js.map +1 -1
  45. package/dist/status.d.ts +20 -2
  46. package/dist/status.d.ts.map +1 -1
  47. package/dist/status.js +59 -45
  48. package/dist/status.js.map +1 -1
  49. package/dist/types.d.ts +46 -30
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +1 -1
  52. package/dist/types.js.map +1 -1
  53. package/package.json +3 -2
  54. package/src/__tests__/devices.test.ts +18 -2
  55. package/src/__tests__/media.test.ts +39 -6
  56. package/src/__tests__/pack-bits.test.ts +92 -0
  57. package/src/__tests__/preview.test.ts +52 -0
  58. package/src/__tests__/protocol.test.ts +47 -1
  59. package/src/__tests__/status.test.ts +31 -22
  60. package/src/devices.ts +41 -22
  61. package/src/index.ts +45 -11
  62. package/src/media.ts +105 -27
  63. package/src/orientation.ts +11 -0
  64. package/src/pack-bits.ts +64 -0
  65. package/src/preview.ts +35 -0
  66. package/src/protocol.ts +16 -9
  67. package/src/status.ts +62 -47
  68. package/src/types.ts +52 -32
package/dist/media.d.ts CHANGED
@@ -1,5 +1,44 @@
1
- import { type MediaDescriptor, type MediaType } from './types.js';
2
- export declare const MEDIA: Record<number, MediaDescriptor>;
3
- export declare function findMedia(id: number): MediaDescriptor | undefined;
4
- export declare function findMediaByWidth(widthMm: number, type: MediaType): MediaDescriptor[];
1
+ import type { BrotherQLMedia, MediaType } from './types.js';
2
+ /**
3
+ * Registry of supported Brother QL consumables.
4
+ *
5
+ * Entries are keyed by the firmware media id — the same number the
6
+ * printer reports in the 32-byte status response. `heightMm` is omitted
7
+ * for continuous media (variable length) and set for die-cut labels
8
+ * (fixed length).
9
+ *
10
+ * `palette` is set on multi-ink media (DK-22251, today's only entry) —
11
+ * the driver routes those through `renderMultiPlaneImage` and emits the
12
+ * second plane in the raster job. Single-ink rolls leave it undefined
13
+ * and route through `renderImage` (dithered single-plane).
14
+ *
15
+ * Rectangular die-cut entries declare `defaultOrientation: 'horizontal'`
16
+ * so landscape input auto-rotates to read along the tape feed direction.
17
+ * Continuous wide tape leaves the hint undefined — users may go either
18
+ * way.
19
+ *
20
+ * `cornerRadiusMm` is informational; previews use it to render the
21
+ * actual paper outline. Round die-cut labels set the radius to
22
+ * `widthMm / 2` so the rounded rectangle degenerates to a circle.
23
+ */
24
+ export declare const MEDIA: Record<number, BrotherQLMedia>;
25
+ /**
26
+ * Default media when `createPreview()` is called without media and
27
+ * without a detected roll. 62mm continuous (DK-22205) is the common
28
+ * single-colour shipping roll.
29
+ */
30
+ export declare const DEFAULT_MEDIA: BrotherQLMedia;
31
+ export declare function findMedia(id: number): BrotherQLMedia | undefined;
32
+ export declare function findMediaByWidth(widthMm: number, type: MediaType): BrotherQLMedia[];
33
+ /**
34
+ * Match status-response dimensions to a media registry entry.
35
+ *
36
+ * @param widthMm media width in mm (status byte 10)
37
+ * @param heightMm media length in mm (status byte 17) — 0 = continuous
38
+ * @param twoColorMode true when the status response indicates the
39
+ * printer is configured for two-colour media. When
40
+ * both DK-22205 (259) and DK-22251 (251) match the
41
+ * dimensions, the flag picks the right one.
42
+ */
43
+ export declare function findMediaByDimensions(widthMm: number, heightMm: number, twoColorMode?: boolean): BrotherQLMedia | undefined;
5
44
  //# sourceMappingURL=media.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAElE,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CA+OjD,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEjE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,eAAe,EAAE,CAEpF"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAmQhD,CAAC;AAEF;;;;GAIG;AAEH,eAAO,MAAM,aAAa,EAAE,cAA4B,CAAC;AAEzD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEhE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,cAAc,EAAE,CAEnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,YAAY,UAAQ,GACnB,cAAc,GAAG,SAAS,CAY5B"}
package/dist/media.js CHANGED
@@ -1,4 +1,25 @@
1
- import {} from './types.js';
1
+ /**
2
+ * Registry of supported Brother QL consumables.
3
+ *
4
+ * Entries are keyed by the firmware media id — the same number the
5
+ * printer reports in the 32-byte status response. `heightMm` is omitted
6
+ * for continuous media (variable length) and set for die-cut labels
7
+ * (fixed length).
8
+ *
9
+ * `palette` is set on multi-ink media (DK-22251, today's only entry) —
10
+ * the driver routes those through `renderMultiPlaneImage` and emits the
11
+ * second plane in the raster job. Single-ink rolls leave it undefined
12
+ * and route through `renderImage` (dithered single-plane).
13
+ *
14
+ * Rectangular die-cut entries declare `defaultOrientation: 'horizontal'`
15
+ * so landscape input auto-rotates to read along the tape feed direction.
16
+ * Continuous wide tape leaves the hint undefined — users may go either
17
+ * way.
18
+ *
19
+ * `cornerRadiusMm` is informational; previews use it to render the
20
+ * actual paper outline. Round die-cut labels set the radius to
21
+ * `widthMm / 2` so the rounded rectangle degenerates to a circle.
22
+ */
2
23
  export const MEDIA = {
3
24
  // Continuous length tape
4
25
  257: {
@@ -6,7 +27,6 @@ export const MEDIA = {
6
27
  name: '12mm continuous',
7
28
  type: 'continuous',
8
29
  widthMm: 12,
9
- lengthMm: 0,
10
30
  printAreaDots: 106,
11
31
  leftMarginPins: 585,
12
32
  rightMarginPins: 29,
@@ -16,7 +36,6 @@ export const MEDIA = {
16
36
  name: '29mm continuous (DK-22210)',
17
37
  type: 'continuous',
18
38
  widthMm: 29,
19
- lengthMm: 0,
20
39
  printAreaDots: 306,
21
40
  leftMarginPins: 408,
22
41
  rightMarginPins: 6,
@@ -26,7 +45,6 @@ export const MEDIA = {
26
45
  name: '38mm continuous (DK-22225)',
27
46
  type: 'continuous',
28
47
  widthMm: 38,
29
- lengthMm: 0,
30
48
  printAreaDots: 413,
31
49
  leftMarginPins: 295,
32
50
  rightMarginPins: 12,
@@ -36,7 +54,6 @@ export const MEDIA = {
36
54
  name: '50mm continuous (DK-22246)',
37
55
  type: 'continuous',
38
56
  widthMm: 50,
39
- lengthMm: 0,
40
57
  printAreaDots: 554,
41
58
  leftMarginPins: 154,
42
59
  rightMarginPins: 12,
@@ -46,7 +63,6 @@ export const MEDIA = {
46
63
  name: '54mm continuous (DK-22214)',
47
64
  type: 'continuous',
48
65
  widthMm: 54,
49
- lengthMm: 0,
50
66
  printAreaDots: 590,
51
67
  leftMarginPins: 130,
52
68
  rightMarginPins: 0,
@@ -56,7 +72,6 @@ export const MEDIA = {
56
72
  name: '62mm continuous (DK-22205)',
57
73
  type: 'continuous',
58
74
  widthMm: 62,
59
- lengthMm: 0,
60
75
  printAreaDots: 696,
61
76
  leftMarginPins: 12,
62
77
  rightMarginPins: 12,
@@ -66,18 +81,19 @@ export const MEDIA = {
66
81
  name: '62mm continuous two-color (DK-22251)',
67
82
  type: 'continuous',
68
83
  widthMm: 62,
69
- lengthMm: 0,
84
+ palette: [
85
+ { name: 'black', rgb: [0, 0, 0] },
86
+ { name: 'red', rgb: [255, 0, 0] },
87
+ ],
70
88
  printAreaDots: 696,
71
89
  leftMarginPins: 12,
72
90
  rightMarginPins: 12,
73
- twoColorTape: true,
74
91
  },
75
92
  260: {
76
93
  id: 260,
77
94
  name: '102mm continuous (DK-22243)',
78
95
  type: 'continuous',
79
96
  widthMm: 102,
80
- lengthMm: 0,
81
97
  printAreaDots: 1164,
82
98
  leftMarginPins: 76,
83
99
  rightMarginPins: 56,
@@ -88,7 +104,9 @@ export const MEDIA = {
88
104
  name: '17×54mm die-cut (DK-11204)',
89
105
  type: 'die-cut',
90
106
  widthMm: 17,
91
- lengthMm: 54,
107
+ heightMm: 54,
108
+ defaultOrientation: 'horizontal',
109
+ cornerRadiusMm: 3,
92
110
  printAreaDots: 165,
93
111
  leftMarginPins: 0,
94
112
  rightMarginPins: 0,
@@ -99,7 +117,9 @@ export const MEDIA = {
99
117
  name: '17×87mm die-cut (DK-11203)',
100
118
  type: 'die-cut',
101
119
  widthMm: 17,
102
- lengthMm: 87,
120
+ heightMm: 87,
121
+ defaultOrientation: 'horizontal',
122
+ cornerRadiusMm: 3,
103
123
  printAreaDots: 165,
104
124
  leftMarginPins: 0,
105
125
  rightMarginPins: 0,
@@ -110,7 +130,9 @@ export const MEDIA = {
110
130
  name: '23×23mm die-cut',
111
131
  type: 'die-cut',
112
132
  widthMm: 23,
113
- lengthMm: 23,
133
+ heightMm: 23,
134
+ defaultOrientation: 'horizontal',
135
+ cornerRadiusMm: 3,
114
136
  printAreaDots: 236,
115
137
  leftMarginPins: 0,
116
138
  rightMarginPins: 0,
@@ -121,7 +143,9 @@ export const MEDIA = {
121
143
  name: '29×90mm die-cut (DK-11201)',
122
144
  type: 'die-cut',
123
145
  widthMm: 29,
124
- lengthMm: 90,
146
+ heightMm: 90,
147
+ defaultOrientation: 'horizontal',
148
+ cornerRadiusMm: 3,
125
149
  printAreaDots: 306,
126
150
  leftMarginPins: 0,
127
151
  rightMarginPins: 0,
@@ -132,7 +156,9 @@ export const MEDIA = {
132
156
  name: '38×90mm die-cut (DK-11218)',
133
157
  type: 'die-cut',
134
158
  widthMm: 38,
135
- lengthMm: 90,
159
+ heightMm: 90,
160
+ defaultOrientation: 'horizontal',
161
+ cornerRadiusMm: 3,
136
162
  printAreaDots: 413,
137
163
  leftMarginPins: 0,
138
164
  rightMarginPins: 0,
@@ -143,7 +169,9 @@ export const MEDIA = {
143
169
  name: '39×48mm die-cut (DK-11219)',
144
170
  type: 'die-cut',
145
171
  widthMm: 39,
146
- lengthMm: 48,
172
+ heightMm: 48,
173
+ defaultOrientation: 'horizontal',
174
+ cornerRadiusMm: 3,
147
175
  printAreaDots: 425,
148
176
  leftMarginPins: 0,
149
177
  rightMarginPins: 0,
@@ -154,7 +182,9 @@ export const MEDIA = {
154
182
  name: '52×29mm die-cut',
155
183
  type: 'die-cut',
156
184
  widthMm: 52,
157
- lengthMm: 29,
185
+ heightMm: 29,
186
+ defaultOrientation: 'horizontal',
187
+ cornerRadiusMm: 3,
158
188
  printAreaDots: 578,
159
189
  leftMarginPins: 0,
160
190
  rightMarginPins: 0,
@@ -165,7 +195,9 @@ export const MEDIA = {
165
195
  name: '62×29mm die-cut (DK-11209)',
166
196
  type: 'die-cut',
167
197
  widthMm: 62,
168
- lengthMm: 29,
198
+ heightMm: 29,
199
+ defaultOrientation: 'horizontal',
200
+ cornerRadiusMm: 3,
169
201
  printAreaDots: 696,
170
202
  leftMarginPins: 0,
171
203
  rightMarginPins: 0,
@@ -176,7 +208,9 @@ export const MEDIA = {
176
208
  name: '62×100mm die-cut (DK-11202)',
177
209
  type: 'die-cut',
178
210
  widthMm: 62,
179
- lengthMm: 100,
211
+ heightMm: 100,
212
+ defaultOrientation: 'horizontal',
213
+ cornerRadiusMm: 3,
180
214
  printAreaDots: 696,
181
215
  leftMarginPins: 0,
182
216
  rightMarginPins: 0,
@@ -187,7 +221,9 @@ export const MEDIA = {
187
221
  name: '102×51mm die-cut (DK-11240)',
188
222
  type: 'die-cut',
189
223
  widthMm: 102,
190
- lengthMm: 51,
224
+ heightMm: 51,
225
+ defaultOrientation: 'horizontal',
226
+ cornerRadiusMm: 3,
191
227
  printAreaDots: 1164,
192
228
  leftMarginPins: 0,
193
229
  rightMarginPins: 0,
@@ -198,7 +234,9 @@ export const MEDIA = {
198
234
  name: '102×152mm die-cut (DK-11241)',
199
235
  type: 'die-cut',
200
236
  widthMm: 102,
201
- lengthMm: 152,
237
+ heightMm: 152,
238
+ defaultOrientation: 'horizontal',
239
+ cornerRadiusMm: 3,
202
240
  printAreaDots: 1164,
203
241
  leftMarginPins: 0,
204
242
  rightMarginPins: 0,
@@ -209,7 +247,8 @@ export const MEDIA = {
209
247
  name: '12mm Ø die-cut',
210
248
  type: 'die-cut',
211
249
  widthMm: 12,
212
- lengthMm: 12,
250
+ heightMm: 12,
251
+ cornerRadiusMm: 6,
213
252
  printAreaDots: 94,
214
253
  leftMarginPins: 0,
215
254
  rightMarginPins: 0,
@@ -220,7 +259,8 @@ export const MEDIA = {
220
259
  name: '24mm Ø die-cut (DK-11221)',
221
260
  type: 'die-cut',
222
261
  widthMm: 24,
223
- lengthMm: 24,
262
+ heightMm: 24,
263
+ cornerRadiusMm: 12,
224
264
  printAreaDots: 236,
225
265
  leftMarginPins: 0,
226
266
  rightMarginPins: 0,
@@ -231,17 +271,45 @@ export const MEDIA = {
231
271
  name: '58mm Ø die-cut (DK-11207)',
232
272
  type: 'die-cut',
233
273
  widthMm: 58,
234
- lengthMm: 58,
274
+ heightMm: 58,
275
+ cornerRadiusMm: 29,
235
276
  printAreaDots: 618,
236
277
  leftMarginPins: 0,
237
278
  rightMarginPins: 0,
238
279
  dieCutMaskedAreaDots: 618,
239
280
  },
240
281
  };
282
+ /**
283
+ * Default media when `createPreview()` is called without media and
284
+ * without a detected roll. 62mm continuous (DK-22205) is the common
285
+ * single-colour shipping roll.
286
+ */
287
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- DK-22205 is a hard-coded registry key
288
+ export const DEFAULT_MEDIA = MEDIA[259];
241
289
  export function findMedia(id) {
242
290
  return MEDIA[id];
243
291
  }
244
292
  export function findMediaByWidth(widthMm, type) {
245
293
  return Object.values(MEDIA).filter(m => m.widthMm === widthMm && m.type === type);
246
294
  }
295
+ /**
296
+ * Match status-response dimensions to a media registry entry.
297
+ *
298
+ * @param widthMm media width in mm (status byte 10)
299
+ * @param heightMm media length in mm (status byte 17) — 0 = continuous
300
+ * @param twoColorMode true when the status response indicates the
301
+ * printer is configured for two-colour media. When
302
+ * both DK-22205 (259) and DK-22251 (251) match the
303
+ * dimensions, the flag picks the right one.
304
+ */
305
+ export function findMediaByDimensions(widthMm, heightMm, twoColorMode = false) {
306
+ if (heightMm === 0) {
307
+ const continuousMatches = Object.values(MEDIA).filter(m => m.type === 'continuous' && m.widthMm === widthMm);
308
+ if (continuousMatches.length === 0)
309
+ return undefined;
310
+ const preferred = continuousMatches.find(m => (m.palette !== undefined) === twoColorMode);
311
+ return preferred ?? continuousMatches[0];
312
+ }
313
+ return Object.values(MEDIA).find(m => m.type === 'die-cut' && m.widthMm === widthMm && m.heightMm === heightMm);
314
+ }
247
315
  //# sourceMappingURL=media.js.map
package/dist/media.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { RotateDirection } from '@thermal-label/contracts';
2
+ /**
3
+ * Direction the Brother QL print head rotates landscape input.
4
+ *
5
+ * `90` = clockwise. Verified once on hardware with a die-cut "F"
6
+ * landscape print (see plan §6 step 1). Identical across every QL
7
+ * model — this is a print-head/leading-edge mechanical fact, not a
8
+ * per-media setting.
9
+ */
10
+ export declare const ROTATE_DIRECTION: RotateDirection;
11
+ //# sourceMappingURL=orientation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orientation.d.ts","sourceRoot":"","sources":["../src/orientation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Direction the Brother QL print head rotates landscape input.
3
+ *
4
+ * `90` = clockwise. Verified once on hardware with a die-cut "F"
5
+ * landscape print (see plan §6 step 1). Identical across every QL
6
+ * model — this is a print-head/leading-edge mechanical fact, not a
7
+ * per-media setting.
8
+ */
9
+ export const ROTATE_DIRECTION = 90;
10
+ //# sourceMappingURL=orientation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orientation.js","sourceRoot":"","sources":["../src/orientation.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAoB,EAAE,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * TIFF-style PackBits row encoder used by Brother QL when compression
3
+ * mode (`M 02`, emitted by `buildCompression(true)`) is enabled for a job.
4
+ *
5
+ * Header byte `n` (interpreted as a signed int8):
6
+ * n in [0, 127]: literal run — the next `n + 1` bytes follow verbatim.
7
+ * n in [-127, -1]: repeat run — the next byte is repeated `1 - n` times.
8
+ * n = -128: no-op. Unused by this encoder.
9
+ *
10
+ * The encoder switches to repeat mode for runs of two or more identical
11
+ * bytes (a 2-byte repeat costs 2 wire bytes; the equivalent 2-byte literal
12
+ * would cost 3). Both run kinds are capped at 128 bytes to fit the header.
13
+ *
14
+ * For a typical Brother QL raster row (90 bytes, mostly zeros in margins
15
+ * and long runs of `0x00` / `0xff` in print area), this compresses to 5–15
16
+ * bytes — a 6–18× reduction. Worst-case for highly random input is one
17
+ * extra byte per 128 (the literal-mode header), i.e. < 1 % expansion.
18
+ */
19
+ export declare function packBits(input: Uint8Array): Uint8Array;
20
+ //# sourceMappingURL=pack-bits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack-bits.d.ts","sourceRoot":"","sources":["../src/pack-bits.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAsCtD"}
@@ -0,0 +1,61 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion --
2
+ * `noUncheckedIndexedAccess` types Uint8Array reads as `number | undefined`
3
+ * but every index in this file is bounded by `i < input.length` or
4
+ * `runEnd < input.length` checks. The `!` assertions collapse the
5
+ * unreachable `undefined` branches so branch coverage doesn't count them.
6
+ */
7
+ /**
8
+ * TIFF-style PackBits row encoder used by Brother QL when compression
9
+ * mode (`M 02`, emitted by `buildCompression(true)`) is enabled for a job.
10
+ *
11
+ * Header byte `n` (interpreted as a signed int8):
12
+ * n in [0, 127]: literal run — the next `n + 1` bytes follow verbatim.
13
+ * n in [-127, -1]: repeat run — the next byte is repeated `1 - n` times.
14
+ * n = -128: no-op. Unused by this encoder.
15
+ *
16
+ * The encoder switches to repeat mode for runs of two or more identical
17
+ * bytes (a 2-byte repeat costs 2 wire bytes; the equivalent 2-byte literal
18
+ * would cost 3). Both run kinds are capped at 128 bytes to fit the header.
19
+ *
20
+ * For a typical Brother QL raster row (90 bytes, mostly zeros in margins
21
+ * and long runs of `0x00` / `0xff` in print area), this compresses to 5–15
22
+ * bytes — a 6–18× reduction. Worst-case for highly random input is one
23
+ * extra byte per 128 (the literal-mode header), i.e. < 1 % expansion.
24
+ */
25
+ export function packBits(input) {
26
+ if (input.length === 0)
27
+ return new Uint8Array(0);
28
+ const out = [];
29
+ let i = 0;
30
+ while (i < input.length) {
31
+ // How many identical bytes start at position i (cap at 128).
32
+ let runEnd = i + 1;
33
+ while (runEnd < input.length && runEnd - i < 128 && input[runEnd] === input[i]) {
34
+ runEnd++;
35
+ }
36
+ const runLen = runEnd - i;
37
+ if (runLen >= 2) {
38
+ // Repeat run: header is signed -(runLen - 1).
39
+ out.push((1 - runLen) & 0xff);
40
+ out.push(input[i]);
41
+ i = runEnd;
42
+ continue;
43
+ }
44
+ // Otherwise emit a literal run. Stop at 128 bytes, or right before a
45
+ // 2+ repeat run starts (cheaper to encode that separately).
46
+ let litEnd = i + 1;
47
+ while (litEnd < input.length && litEnd - i < 128) {
48
+ if (litEnd + 1 < input.length && input[litEnd] === input[litEnd + 1]) {
49
+ break;
50
+ }
51
+ litEnd++;
52
+ }
53
+ const litLen = litEnd - i;
54
+ out.push(litLen - 1);
55
+ for (let x = i; x < litEnd; x++)
56
+ out.push(input[x]);
57
+ i = litEnd;
58
+ }
59
+ return new Uint8Array(out);
60
+ }
61
+ //# sourceMappingURL=pack-bits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack-bits.js","sourceRoot":"","sources":["../src/pack-bits.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAiB;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAEjD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,6DAA6D;QAC7D,IAAI,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/E,MAAM,EAAE,CAAC;QACX,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;QAE1B,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YAChB,8CAA8C;YAC9C,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YAC9B,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YACpB,CAAC,GAAG,MAAM,CAAC;YACX,SAAS;QACX,CAAC;QAED,qEAAqE;QACrE,4DAA4D;QAC5D,IAAI,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC;YACjD,IAAI,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrE,MAAM;YACR,CAAC;YACD,MAAM,EAAE,CAAC;QACX,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;QAC1B,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QACrD,CAAC,GAAG,MAAM,CAAC;IACb,CAAC;IAED,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { RawImageData } from '@mbtech-nl/bitmap';
2
+ import type { PreviewResult } from '@thermal-label/contracts';
3
+ import type { BrotherQLMedia } from './types.js';
4
+ /**
5
+ * Offline preview without a live printer connection.
6
+ *
7
+ * Multi-ink aware: when `media.palette` is defined (DK-22251 today),
8
+ * the image is split per-plane via `renderMultiPlaneImage()` — the
9
+ * same code path `print()` takes for that media. Single-ink media
10
+ * returns one black plane via dithered `renderImage`.
11
+ */
12
+ export declare function createPreviewOffline(image: RawImageData, media: BrotherQLMedia): PreviewResult;
13
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,GAAG,aAAa,CAqB9F"}
@@ -0,0 +1,31 @@
1
+ import { renderImage, renderMultiPlaneImage } from '@mbtech-nl/bitmap';
2
+ /**
3
+ * Offline preview without a live printer connection.
4
+ *
5
+ * Multi-ink aware: when `media.palette` is defined (DK-22251 today),
6
+ * the image is split per-plane via `renderMultiPlaneImage()` — the
7
+ * same code path `print()` takes for that media. Single-ink media
8
+ * returns one black plane via dithered `renderImage`.
9
+ */
10
+ export function createPreviewOffline(image, media) {
11
+ if (media.palette) {
12
+ const planes = renderMultiPlaneImage(image, {
13
+ palette: media.palette,
14
+ });
15
+ return {
16
+ planes: [
17
+ { name: 'black', bitmap: planes.black, displayColor: '#000000' },
18
+ { name: 'red', bitmap: planes.red, displayColor: '#ff0000' },
19
+ ],
20
+ media,
21
+ assumed: false,
22
+ };
23
+ }
24
+ const bitmap = renderImage(image, { dither: true });
25
+ return {
26
+ planes: [{ name: 'black', bitmap, displayColor: '#000000' }],
27
+ media,
28
+ assumed: false,
29
+ };
30
+ }
31
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../src/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAKvE;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAmB,EAAE,KAAqB;IAC7E,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,EAAE;YAC1C,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAyC,CAAC;QAC3C,OAAO;YACL,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE;gBAChE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE;aAC7D;YACD,KAAK;YACL,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,OAAO;QACL,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;QAC5D,KAAK;QACL,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC"}
@@ -1,10 +1,10 @@
1
- import { type MediaDescriptor, type PageData, type JobOptions } from './types.js';
1
+ import type { BrotherQLMedia, PageData, JobOptions } from './types.js';
2
2
  export declare function buildInvalidate(): Uint8Array;
3
3
  export declare function buildStatusRequest(): Uint8Array;
4
4
  export declare function buildInitialize(): Uint8Array;
5
5
  export declare function buildRasterMode(): Uint8Array;
6
6
  export declare function buildStatusNotification(enabled: boolean): Uint8Array;
7
- export declare function buildPrintInfo(media: MediaDescriptor, rowCount: number, pageIndex: number): Uint8Array;
7
+ export declare function buildPrintInfo(media: BrotherQLMedia, rowCount: number, pageIndex: number): Uint8Array;
8
8
  export declare function buildVariousMode(autoCut: boolean): Uint8Array;
9
9
  export declare function buildExpandedMode(cutAtEnd: boolean, highRes: boolean, twoColor?: boolean): Uint8Array;
10
10
  export declare function buildCutEach(n: number): Uint8Array;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAoB,MAAM,YAAY,CAAC;AAEpG,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAEpE;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,UAAU,CAsBZ;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAE7D;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,EAChB,QAAQ,UAAQ,GACf,UAAU,CAMZ;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAElD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAE7D;AAKD,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,OAAO,GAAG,KAAK,EACtB,QAAQ,UAAQ,GACf,UAAU,CAYZ;AAED,wBAAgB,YAAY,IAAI,UAAU,CAEzC;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAEjE;AA8BD,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,UAAU,CA4EjF"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAe,MAAM,YAAY,CAAC;AAEpF,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAEpE;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,UAAU,CAsBZ;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAE7D;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,EAChB,QAAQ,UAAQ,GACf,UAAU,CAMZ;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAElD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAE7D;AAKD,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,OAAO,GAAG,KAAK,EACtB,QAAQ,UAAQ,GACf,UAAU,CAYZ;AAED,wBAAgB,YAAY,IAAI,UAAU,CAEzC;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAEjE;AA8BD,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,UAAU,CAkFjF"}
package/dist/protocol.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getRow, createBitmap } from '@mbtech-nl/bitmap';
2
- import {} from './types.js';
2
+ import { packBits } from './pack-bits.js';
3
3
  export function buildInvalidate() {
4
4
  return new Uint8Array(200);
5
5
  }
@@ -28,7 +28,7 @@ export function buildPrintInfo(media, rowCount, pageIndex) {
28
28
  buf[3] = validFlags;
29
29
  buf[4] = mediaType;
30
30
  buf[5] = media.widthMm;
31
- buf[6] = media.lengthMm;
31
+ buf[6] = media.heightMm ?? 0;
32
32
  // rowCount little-endian at bytes 7-8 (offsets 4-5 in param block)
33
33
  buf[7] = rowCount & 0xff;
34
34
  buf[8] = (rowCount >> 8) & 0xff;
@@ -128,11 +128,11 @@ export function encodeJob(pages, options = {}) {
128
128
  const marginDots = opts.marginDots ?? 35;
129
129
  const compress = opts.compress ?? false;
130
130
  const { bitmap, media } = page;
131
- // twoColorTape media (e.g. DK-22251) requires two-color mode even for black-only jobs.
131
+ // Multi-ink media (e.g. DK-22251) requires two-color mode even for black-only jobs.
132
132
  // Auto-create an empty red plane when the tape demands it but caller didn't supply one.
133
- const twoColor = page.redBitmap !== undefined || media.twoColorTape === true;
134
- const redBitmap = page.redBitmap ??
135
- (media.twoColorTape ? createBitmap(bitmap.widthPx, bitmap.heightPx) : undefined);
133
+ const multiInk = media.palette !== undefined;
134
+ const twoColor = page.redBitmap !== undefined || multiInk;
135
+ const redBitmap = page.redBitmap ?? (multiInk ? createBitmap(bitmap.widthPx, bitmap.heightPx) : undefined);
136
136
  if (twoColor && redBitmap !== undefined) {
137
137
  if (bitmap.widthPx !== redBitmap.widthPx || bitmap.heightPx !== redBitmap.heightPx) {
138
138
  throw new Error('Two-color bitmaps must have identical dimensions');
@@ -154,16 +154,22 @@ export function encodeJob(pages, options = {}) {
154
154
  const rowByteLen = Math.ceil(totalPins / 8);
155
155
  // Rows interleaved per raster line (matches Python brother_ql behaviour).
156
156
  // Two-color: black row then red row for each line. Single-color: black only.
157
+ // When `compress` is on, each row's bytes are PackBits-encoded and the
158
+ // raster-row LEN byte carries the compressed length. The printer was
159
+ // already switched into compression mode by `buildCompression(true)`
160
+ // above, so it expects every subsequent row to be PackBits.
157
161
  for (let r = 0; r < rowCount; r++) {
158
162
  const blackSrc = getRow(bitmap, r);
159
163
  const blackBytes = new Uint8Array(rowByteLen);
160
164
  placeBits(blackSrc, bitmap.widthPx, blackBytes, media.leftMarginPins);
161
- chunks.push(buildRasterRow(blackBytes, 'black', twoColor));
165
+ const blackPayload = compress ? packBits(blackBytes) : blackBytes;
166
+ chunks.push(buildRasterRow(blackPayload, 'black', twoColor));
162
167
  if (twoColor && redBitmap !== undefined) {
163
168
  const redSrc = getRow(redBitmap, r);
164
169
  const redBytes = new Uint8Array(rowByteLen);
165
170
  placeBits(redSrc, redBitmap.widthPx, redBytes, media.leftMarginPins);
166
- chunks.push(buildRasterRow(redBytes, 'red', twoColor));
171
+ const redPayload = compress ? packBits(redBytes) : redBytes;
172
+ chunks.push(buildRasterRow(redPayload, 'red', twoColor));
167
173
  }
168
174
  }
169
175
  chunks.push(buildPrintCommand(isLastPage));