Skip to content

Commit d3fd583

Browse files
authored
Merge pull request #95 from u8array/fix/reverse-text-gb-fr
fix(zpl): reverse text uses ^GB+^FR knockout pattern instead of ^LR
2 parents 8c36535 + 687fd77 commit d3fd583

6 files changed

Lines changed: 268 additions & 73 deletions

File tree

‎src/components/Canvas/KonvaObject.tsx‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,14 @@ function KonvaObjectInner({
277277
// Use the measured ink width (already in dot space, mirrored to
278278
// CSS px via dotsToPx) so the inverted background bbox tracks the
279279
// actual rendered text rather than a length-based guess.
280+
// Match the printer's ^GB knockout-background exactly: width =
281+
// measured ink width, height = font height in CSS px. Earlier
282+
// versions padded the height to 1.3× for visual breathing room
283+
// but that hid what the printer actually emits — the canvas now
284+
// mirrors the same `^GB inkW, fontHeight` shape the generator
285+
// produces, so the preview matches Labelary and the real device.
280286
const approxW = dotsToPx(textMetrics.inkWidthDots, scale, dpmm);
281-
const approxH = fontSizePx * 1.3;
287+
const approxH = fontSizePx;
282288
return (
283289
<Group
284290
id={obj.id}
@@ -309,7 +315,7 @@ function KonvaObjectInner({
309315
fontStyle="bold"
310316
scaleX={fontScaleX}
311317
fill="#ffffff"
312-
y={approxH * 0.1}
318+
y={0}
313319
/>
314320
</Group>
315321
);

‎src/lib/zplGenerator.test.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ describe('generateZPL — structure', () => {
5555
expect(zpl).toContain('^LS5');
5656
});
5757

58+
it('reverse text round-trips: emit ^GB+^FR, parse collapses back to one reverse text', () => {
59+
// Generator emits a filled black ^GB knockout-background followed by
60+
// an ^FR text at the same anchor. The parser detects that pair and
61+
// collapses it back into a single text object with reverse:true —
62+
// so the editor never sees two objects after a save/load cycle.
63+
const objs = [
64+
{ id: 'r', type: 'text', x: 50, y: 50, rotation: 0,
65+
props: { content: 'Hi', fontHeight: 30, fontWidth: 0, rotation: 'N', reverse: true } },
66+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
67+
] as any;
68+
const zpl = generateZPL(BASE_LABEL, objs);
69+
expect(zpl).toContain('^GB');
70+
expect(zpl).toContain('^FR^FD');
71+
expect(zpl).not.toContain('^LRY');
72+
const { objects } = parseZPL(zpl, 8);
73+
expect(objects).toHaveLength(1);
74+
expect(objects[0]?.type).toBe('text');
75+
expect(props(objects[0]).reverse).toBe(true);
76+
expect(props(objects[0]).content).toBe('Hi');
77+
});
78+
5879
it('omits objects with includeInExport=false', () => {
5980
const objs = [
6081
{ id: 'a', type: 'text', x: 10, y: 10, rotation: 0, props: { content: 'KEEP', fontHeight: 30, fontWidth: 0, rotation: 'N', reverse: false } },

‎src/lib/zplParser.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ describe('parseZPL — ^FR field reverse', () => {
136136
const { objects } = parseZPL('^XA^FO0,0^A0N,30,0^FDNormal^FS^XZ', 8);
137137
expect(props(objects[0]).reverse).toBeFalsy();
138138
});
139+
140+
it('keeps an unrelated filled box + ^FR text at a different anchor as two objects', () => {
141+
// Anchor mismatch ⇒ no collapse. Hand-written ZPL where a black box
142+
// and an ^FR text happen to coexist must round-trip unchanged.
143+
const { objects } = parseZPL(
144+
'^XA^FO10,10^GB60,30,60,B,0^FS^FO200,200^A0N,30,0^FR^FDHi^FS^XZ',
145+
8,
146+
);
147+
expect(objects).toHaveLength(2);
148+
expect(objects[0]?.type).toBe('box');
149+
expect(objects[1]?.type).toBe('text');
150+
expect(props(objects[1]).reverse).toBe(true);
151+
});
139152
});
140153

141154
// ── shapes ────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)