@kreiseck/kasseneck-api 0.23.0 → 0.26.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 (102) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/cjs/kasse/drucker.d.ts +1 -1
  3. package/dist/cjs/printing/escpos.d.ts +30 -5
  4. package/dist/cjs/printing/escpos.js +84 -34
  5. package/dist/cjs/react/index.js +6 -0
  6. package/dist/cjs/receipt/blatt.d.ts +5 -3
  7. package/dist/cjs/receipt/blatt.js +11 -10
  8. package/dist/cjs/receipt/epos.d.ts +2 -2
  9. package/dist/cjs/receipt/epos.js +8 -0
  10. package/dist/cjs/receipt/index.d.ts +3 -1
  11. package/dist/cjs/receipt/index.js +6 -2
  12. package/dist/cjs/receipt/layout-escpos.d.ts +1 -1
  13. package/dist/cjs/receipt/layout-escpos.js +4 -0
  14. package/dist/cjs/receipt/marke-daten.d.ts +14 -0
  15. package/dist/cjs/receipt/marke-daten.js +18 -0
  16. package/dist/cjs/receipt/marke.d.ts +20 -0
  17. package/dist/cjs/receipt/marke.js +46 -0
  18. package/dist/esm/kasse/drucker.d.ts +1 -1
  19. package/dist/esm/printing/escpos.d.ts +30 -5
  20. package/dist/esm/printing/escpos.js +83 -34
  21. package/dist/esm/react/index.js +7 -1
  22. package/dist/esm/receipt/blatt.d.ts +5 -3
  23. package/dist/esm/receipt/blatt.js +10 -9
  24. package/dist/esm/receipt/epos.d.ts +2 -2
  25. package/dist/esm/receipt/epos.js +8 -0
  26. package/dist/esm/receipt/index.d.ts +3 -1
  27. package/dist/esm/receipt/index.js +3 -1
  28. package/dist/esm/receipt/layout-escpos.d.ts +1 -1
  29. package/dist/esm/receipt/layout-escpos.js +4 -0
  30. package/dist/esm/receipt/marke-daten.d.ts +14 -0
  31. package/dist/esm/receipt/marke-daten.js +15 -0
  32. package/dist/esm/receipt/marke.d.ts +20 -0
  33. package/dist/esm/receipt/marke.js +42 -0
  34. package/fixtures/erwartet/karte-eigener.blatt32.json +3 -4
  35. package/fixtures/erwartet/karte-eigener.blatt48.json +3 -4
  36. package/fixtures/erwartet/karte-gptom-ios.blatt32.json +3 -4
  37. package/fixtures/erwartet/karte-gptom-ios.blatt48.json +3 -4
  38. package/fixtures/erwartet/karte-gptom.blatt32.json +3 -4
  39. package/fixtures/erwartet/karte-gptom.blatt48.json +3 -4
  40. package/fixtures/erwartet/karte-hobex-cloud.blatt32.json +3 -4
  41. package/fixtures/erwartet/karte-hobex-cloud.blatt48.json +3 -4
  42. package/fixtures/erwartet/karte-hobex-hps.blatt32.json +3 -4
  43. package/fixtures/erwartet/karte-hobex-hps.blatt48.json +3 -4
  44. package/fixtures/erwartet/karte-mypos.blatt32.json +3 -4
  45. package/fixtures/erwartet/karte-mypos.blatt48.json +3 -4
  46. package/fixtures/erwartet/karte-stripe-eps.blatt32.json +3 -4
  47. package/fixtures/erwartet/karte-stripe-eps.blatt48.json +3 -4
  48. package/fixtures/erwartet/karte-stripe.blatt32.json +3 -4
  49. package/fixtures/erwartet/karte-stripe.blatt48.json +3 -4
  50. package/fixtures/erwartet/karte-sumup.blatt32.json +3 -4
  51. package/fixtures/erwartet/karte-sumup.blatt48.json +3 -4
  52. package/fixtures/erwartet/langer-artikelname.blatt32.json +3 -4
  53. package/fixtures/erwartet/langer-artikelname.blatt48.json +3 -4
  54. package/fixtures/erwartet/null-ausfall.blatt32.json +3 -4
  55. package/fixtures/erwartet/null-ausfall.blatt48.json +3 -4
  56. package/fixtures/erwartet/null-jahr.blatt32.json +3 -4
  57. package/fixtures/erwartet/null-jahr.blatt48.json +3 -4
  58. package/fixtures/erwartet/null-monat.blatt32.json +3 -4
  59. package/fixtures/erwartet/null-monat.blatt48.json +3 -4
  60. package/fixtures/erwartet/null-pruef.blatt32.json +3 -4
  61. package/fixtures/erwartet/null-pruef.blatt48.json +3 -4
  62. package/fixtures/erwartet/null-schluss.blatt32.json +3 -4
  63. package/fixtures/erwartet/null-schluss.blatt48.json +3 -4
  64. package/fixtures/erwartet/null-start.blatt32.json +3 -4
  65. package/fixtures/erwartet/null-start.blatt48.json +3 -4
  66. package/fixtures/erwartet/rabatt-chef-trinkgeld.blatt32.json +3 -4
  67. package/fixtures/erwartet/rabatt-chef-trinkgeld.blatt48.json +3 -4
  68. package/fixtures/erwartet/rabatt-einfach.blatt32.json +3 -4
  69. package/fixtures/erwartet/rabatt-einfach.blatt48.json +3 -4
  70. package/fixtures/erwartet/rabatt-trinkgeld.blatt32.json +3 -4
  71. package/fixtures/erwartet/rabatt-trinkgeld.blatt48.json +3 -4
  72. package/fixtures/erwartet/rabatt-wertgutschein.blatt32.json +3 -4
  73. package/fixtures/erwartet/rabatt-wertgutschein.blatt48.json +3 -4
  74. package/fixtures/erwartet/rabattzeilen.blatt32.json +3 -4
  75. package/fixtures/erwartet/rabattzeilen.blatt48.json +3 -4
  76. package/fixtures/erwartet/signaturausfall-verkauf.blatt32.json +3 -4
  77. package/fixtures/erwartet/signaturausfall-verkauf.blatt48.json +3 -4
  78. package/fixtures/erwartet/storno-rabatt.blatt32.json +3 -4
  79. package/fixtures/erwartet/storno-rabatt.blatt48.json +3 -4
  80. package/fixtures/erwartet/storno-teil.blatt32.json +3 -4
  81. package/fixtures/erwartet/storno-teil.blatt48.json +3 -4
  82. package/fixtures/erwartet/storno-voll.blatt32.json +3 -4
  83. package/fixtures/erwartet/storno-voll.blatt48.json +3 -4
  84. package/fixtures/erwartet/testkasse-verkauf.blatt32.json +3 -4
  85. package/fixtures/erwartet/testkasse-verkauf.blatt48.json +3 -4
  86. package/fixtures/erwartet/testsignatur-verkauf.blatt32.json +3 -4
  87. package/fixtures/erwartet/testsignatur-verkauf.blatt48.json +3 -4
  88. package/fixtures/erwartet/training.blatt32.json +3 -4
  89. package/fixtures/erwartet/training.blatt48.json +3 -4
  90. package/fixtures/erwartet/verkauf-bar.blatt32.json +3 -4
  91. package/fixtures/erwartet/verkauf-bar.blatt48.json +3 -4
  92. package/fixtures/erwartet/verkauf-karte.blatt32.json +3 -4
  93. package/fixtures/erwartet/verkauf-karte.blatt48.json +3 -4
  94. package/fixtures/erwartet/verkauf-kleinunternehmer.blatt32.json +3 -4
  95. package/fixtures/erwartet/verkauf-kleinunternehmer.blatt48.json +3 -4
  96. package/fixtures/hobex-hps-codes.json +1 -1
  97. package/fixtures/kasse-texte.json +1 -1
  98. package/fixtures/manifest.json +62 -62
  99. package/fixtures/oberflaeche.json +1 -1
  100. package/fixtures/rechnung-api.schema.json +1 -1
  101. package/fixtures/rechnung-texte.json +1 -1
  102. package/package.json +2 -1
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entpackeRasterBits = entpackeRasterBits;
4
+ exports.markeBild = markeBild;
5
+ const marke_daten_js_1 = require("./marke-daten.js");
6
+ /** Base64 -> Bytes ohne `Buffer` -- laeuft im Browser und in Node gleich (wie `rasterZeilenBase64`). */
7
+ function base64Bytes(base64) {
8
+ const binaer = atob(base64);
9
+ const bytes = new Uint8Array(binaer.length);
10
+ for (let i = 0; i < binaer.length; i++)
11
+ bytes[i] = binaer.charCodeAt(i);
12
+ return bytes;
13
+ }
14
+ /**
15
+ * Entpackt gepackte Rasterzeilen (Base64, MSB zuerst, je Zeile auf volle Bytes
16
+ * aufgefuellt -- die Form von [rasterZeilenBytes]) in ein Punkt-je-Byte-Bild.
17
+ *
18
+ * Eigene, exportierte Funktion statt Code inline in `markeBild`: ein
19
+ * Rundlauf-Test (packen mit `rasterZeilenBytes`, entpacken hiermit) kann so
20
+ * denselben Entpacker pruefen, den die Marke zur Laufzeit auch benutzt --
21
+ * ein vertauschter Bit-Index waere sonst nur am schiefen Ausdruck sichtbar.
22
+ */
23
+ function entpackeRasterBits(bits, breite, hoehe) {
24
+ const byteJeZeile = Math.ceil(breite / 8);
25
+ const roh = base64Bytes(bits);
26
+ const punkte = new Uint8Array(breite * hoehe);
27
+ for (let y = 0; y < hoehe; y++) {
28
+ for (let x = 0; x < breite; x++) {
29
+ const byte = roh[y * byteJeZeile + (x >> 3)];
30
+ punkte[y * breite + x] = (byte >> (7 - (x & 7))) & 1;
31
+ }
32
+ }
33
+ return { breite, hoehe, punkte };
34
+ }
35
+ /**
36
+ * Die Marke als Rasterbild fuer diese Papierbreite.
37
+ *
38
+ * Entpackt die gepackten Zeilen in ein Punkt-je-Byte-Bild, wie es
39
+ * [escPosRasterBild] erwartet. Zur Laufzeit wird nichts gerechnet und nichts
40
+ * skaliert -- die beiden Masse stehen fest, damit JS und Dart fuer denselben
41
+ * Beleg dieselben Bytes erzeugen.
42
+ */
43
+ function markeBild(paperSize) {
44
+ const d = marke_daten_js_1.MARKE_RASTER[paperSize];
45
+ return entpackeRasterBits(d.bits, d.breite, d.hoehe);
46
+ }
@@ -49,7 +49,7 @@ export interface CreatePrintJobOptions {
49
49
  quelle?: string;
50
50
  /** Firmenlogo als fertiges Rasterbild (`logoRaster`); der Server dekodiert keine Bilder. */
51
51
  logo?: DruckLogo | null;
52
- /** "erstellt mit Kasseneck" am Ende (Konto-Flag `kreiseck_logo`). */
52
+ /** Das Kasseneck-Logo am Ende (Konto-Flag `kreiseck_logo`). */
53
53
  marke?: boolean;
54
54
  }
55
55
  export declare function createPrintJob(rufen: InternerTransport, o: CreatePrintJobOptions): Promise<DruckJob>;
@@ -189,6 +189,25 @@ export declare function escPosBytes(doc: EscPosDocument): Uint8Array;
189
189
  * sie beim Initialisieren.
190
190
  */
191
191
  export declare function escPosReset(doc: EscPosDocument): void;
192
+ /**
193
+ * `GS L` + `GS W`: linker Rand auf 0, Druckbereich auf die Breite des Blatts.
194
+ *
195
+ * **Warum das noetig ist.** `ESC a 1` mittelt nicht im Blatt, sondern im
196
+ * Druckbereich des *Geraets*. Steht das Blatt auf 58 mm (32 Zeichen) und
197
+ * haengt ein 80-mm-Drucker daran, setzt er den Text in die linken 384 Punkte,
198
+ * mittelt QR, Logo und Marke aber in seinen 576 -- am Papier sitzt dann alles
199
+ * Bildhafte gegenueber dem Text nach rechts gerueckt. Am Geraet nachgestellt
200
+ * und bestaetigt: mit diesen acht Bytes im Vorspann steht beides buendig.
201
+ *
202
+ * Der Befehl beschreibt also nicht das Papier, sondern das Blatt: er sagt dem
203
+ * Drucker, welche Flaeche gemeint ist, statt ihn raten zu lassen. Passt das
204
+ * Geraet ohnehin zum Blatt (der Regelfall), ist es sein eigener Vorgabewert
205
+ * und aendert am Druckbild nichts.
206
+ *
207
+ * Es ist dieselbe Fehlerklasse wie in 0.24.0 und 0.25.0: eine Ausrichtung,
208
+ * die sich am falschen Bezug orientiert.
209
+ */
210
+ export declare function escPosSetDruckbereich(doc: EscPosDocument): void;
192
211
  /**
193
212
  * `ESC t n`: Codepage waehlen. Sie gilt bis zum naechsten `escPosReset` und
194
213
  * wird von diesem erneut gesendet. `null` schaltet die Vorgabe ab; dann
@@ -206,12 +225,18 @@ export declare function escPosSetGlobalFont(doc: EscPosDocument, font: PosFont |
206
225
  * Sendet die Stilbefehle, die sich gegenueber dem zuletzt gesendeten Stand
207
226
  * geaendert haben. Fehlende Felder in [styles] gelten als Vorgabe: wer fett
208
227
  * weglaesst, schaltet fett also ab.
228
+ *
229
+ * `zeilenanfang` (Vorgabe `true`) sagt, ob dieser Aufruf am Anfang einer
230
+ * Druckzeile steht. Nur dort nimmt der Drucker `ESC a` (Ausrichtung)
231
+ * ueberhaupt an; mitten in der Zeile verwirft er den Befehl wortlos. Der
232
+ * Bytestrom bekommt ihn trotzdem -- die Bytefolge soll sich dadurch nicht
233
+ * aendern --, aber der intern gemerkte Zustand darf sich NICHT auf den neuen
234
+ * Wert stellen: sonst haelt eine spaetere, echte Zeile die Ausrichtung
235
+ * faelschlich schon fuer gesetzt und unterlaesst den Befehl.
209
236
  */
210
- export declare function escPosSetStyles(doc: EscPosDocument, styles?: PosStyles): void;
211
- /**
212
- * Interner Textdruck: absolute Position setzen (`ESC $`), Stil senden, Bytes
213
- * ausgeben. [colInd]/[colWidth] beschreiben die Spalte im Zwoelftel-Raster.
214
- */
237
+ export declare function escPosSetStyles(doc: EscPosDocument, styles?: PosStyles, optionen?: {
238
+ zeilenanfang?: boolean;
239
+ }): void;
215
240
  /**
216
241
  * Wortweiser Umbruch von (kodierten) Text-Bytes auf hoechstens `max` Zeichen
217
242
  * je Zeile: geschnitten wird am letzten Leerzeichen innerhalb der Grenze
@@ -46,6 +46,8 @@ const C_UNDERLINE_OFF = [ESC, 0x2d, 0x00]; // ESC - 0
46
46
  const C_UNDERLINE_1DOT = [ESC, 0x2d, 0x01]; // ESC - 1
47
47
  const C_BOLD_ON = [ESC, 0x45, 0x01]; // ESC E 1
48
48
  const C_BOLD_OFF = [ESC, 0x45, 0x00]; // ESC E 0
49
+ const C_LEFT_MARGIN = [GS, 0x4c]; // GS L nL nH
50
+ const C_PRINT_AREA = [GS, 0x57]; // GS W nL nH
49
51
  const C_FONT_A = [ESC, 0x4d, 0x00]; // ESC M 0
50
52
  const C_FONT_B = [ESC, 0x4d, 0x01]; // ESC M 1
51
53
  const C_TURN90_ON = [ESC, 0x56, 0x01]; // ESC V 1
@@ -67,6 +69,14 @@ const QR_KORREKTUR = { L: 48, M: 49, Q: 50, H: 51 };
67
69
  const PAPIER_MM = { mm58: 58, mm80: 80 };
68
70
  /** Druckbreite in Punkten je Papierformat — aus enums.dart (EscPaperSize.width). */
69
71
  const PAPIER_BREITE = { mm58: 372, mm80: 558 };
72
+ /**
73
+ * Breite des **Blatts** in Punkten: Zeichen je Zeile in Font A mal 12 Punkte.
74
+ *
75
+ * Das ist bewusst NICHT `PAPIER_BREITE` (372/558, das Erbe aus enums.dart fuer
76
+ * die Spaltenrechnung), sondern das Raster, in dem der Text wirklich steht --
77
+ * ein Zeichen in Font A ist 12 Punkte breit, 32 Zeichen also 384 Punkte.
78
+ */
79
+ const BLATT_PUNKTE = { mm58: 32 * 12, mm80: 48 * 12 };
70
80
  /** Zeichen je Zeile nach Papier und Schrift — aus generator.dart. */
71
81
  const ZEICHEN_JE_ZEILE = {
72
82
  mm58: { fontA: 32, fontB: 42 },
@@ -230,6 +240,7 @@ export function escPosBytes(doc) {
230
240
  */
231
241
  export function escPosReset(doc) {
232
242
  anhaengen(doc, C_INIT);
243
+ escPosSetDruckbereich(doc);
233
244
  doc.styles = vollstaendigeStile();
234
245
  // Wie `PrintPaper.reset()` im Flutter-Zwilling: ein neu begonnener Beleg
235
246
  // erbt die QR-Meldungen des vorigen nicht.
@@ -238,6 +249,29 @@ export function escPosReset(doc) {
238
249
  escPosSetGlobalCodeTable(doc, doc.globalCodeTable);
239
250
  escPosSetGlobalFont(doc, doc.globalFont);
240
251
  }
252
+ /**
253
+ * `GS L` + `GS W`: linker Rand auf 0, Druckbereich auf die Breite des Blatts.
254
+ *
255
+ * **Warum das noetig ist.** `ESC a 1` mittelt nicht im Blatt, sondern im
256
+ * Druckbereich des *Geraets*. Steht das Blatt auf 58 mm (32 Zeichen) und
257
+ * haengt ein 80-mm-Drucker daran, setzt er den Text in die linken 384 Punkte,
258
+ * mittelt QR, Logo und Marke aber in seinen 576 -- am Papier sitzt dann alles
259
+ * Bildhafte gegenueber dem Text nach rechts gerueckt. Am Geraet nachgestellt
260
+ * und bestaetigt: mit diesen acht Bytes im Vorspann steht beides buendig.
261
+ *
262
+ * Der Befehl beschreibt also nicht das Papier, sondern das Blatt: er sagt dem
263
+ * Drucker, welche Flaeche gemeint ist, statt ihn raten zu lassen. Passt das
264
+ * Geraet ohnehin zum Blatt (der Regelfall), ist es sein eigener Vorgabewert
265
+ * und aendert am Druckbild nichts.
266
+ *
267
+ * Es ist dieselbe Fehlerklasse wie in 0.24.0 und 0.25.0: eine Ausrichtung,
268
+ * die sich am falschen Bezug orientiert.
269
+ */
270
+ export function escPosSetDruckbereich(doc) {
271
+ const punkte = BLATT_PUNKTE[doc.paperSize];
272
+ anhaengen(doc, [...C_LEFT_MARGIN, 0, 0]);
273
+ anhaengen(doc, [...C_PRINT_AREA, punkte & 0xff, punkte >> 8]);
274
+ }
241
275
  /**
242
276
  * `ESC t n`: Codepage waehlen. Sie gilt bis zum naechsten `escPosReset` und
243
277
  * wird von diesem erneut gesendet. `null` schaltet die Vorgabe ab; dann
@@ -273,13 +307,23 @@ export function escPosSetGlobalFont(doc, font, options = {}) {
273
307
  * Sendet die Stilbefehle, die sich gegenueber dem zuletzt gesendeten Stand
274
308
  * geaendert haben. Fehlende Felder in [styles] gelten als Vorgabe: wer fett
275
309
  * weglaesst, schaltet fett also ab.
310
+ *
311
+ * `zeilenanfang` (Vorgabe `true`) sagt, ob dieser Aufruf am Anfang einer
312
+ * Druckzeile steht. Nur dort nimmt der Drucker `ESC a` (Ausrichtung)
313
+ * ueberhaupt an; mitten in der Zeile verwirft er den Befehl wortlos. Der
314
+ * Bytestrom bekommt ihn trotzdem -- die Bytefolge soll sich dadurch nicht
315
+ * aendern --, aber der intern gemerkte Zustand darf sich NICHT auf den neuen
316
+ * Wert stellen: sonst haelt eine spaetere, echte Zeile die Ausrichtung
317
+ * faelschlich schon fuer gesetzt und unterlaesst den Befehl.
276
318
  */
277
- export function escPosSetStyles(doc, styles = {}) {
319
+ export function escPosSetStyles(doc, styles = {}, optionen = {}) {
278
320
  const neu = vollstaendigeStile(styles);
279
321
  const alt = doc.styles;
322
+ const zeilenanfang = optionen.zeilenanfang ?? true;
280
323
  if (neu.align !== alt.align) {
281
324
  anhaengen(doc, neu.align === 'left' ? C_ALIGN_LEFT : neu.align === 'center' ? C_ALIGN_CENTER : C_ALIGN_RIGHT);
282
- alt.align = neu.align;
325
+ if (zeilenanfang)
326
+ alt.align = neu.align;
283
327
  }
284
328
  if (neu.bold !== alt.bold) {
285
329
  anhaengen(doc, neu.bold ? C_BOLD_ON : C_BOLD_OFF);
@@ -319,10 +363,6 @@ export function escPosSetStyles(doc, styles = {}) {
319
363
  alt.codeTable = codepage;
320
364
  }
321
365
  }
322
- /**
323
- * Interner Textdruck: absolute Position setzen (`ESC $`), Stil senden, Bytes
324
- * ausgeben. [colInd]/[colWidth] beschreiben die Spalte im Zwoelftel-Raster.
325
- */
326
366
  /**
327
367
  * Wortweiser Umbruch von (kodierten) Text-Bytes auf hoechstens `max` Zeichen
328
368
  * je Zeile: geschnitten wird am letzten Leerzeichen innerhalb der Grenze
@@ -424,27 +464,49 @@ export function wortzeilenText(text, max) {
424
464
  out.push(rest.replace(/\u00a0/g, ' '));
425
465
  return out;
426
466
  }
467
+ /**
468
+ * Interner Textdruck: Stil senden (Ausrichtung zuerst), absolute Position
469
+ * setzen (`ESC $`, ausser bei einer vollen Zeile), Bytes ausgeben. [colInd]/
470
+ * [colWidth] beschreiben die Spalte im Zwoelftel-Raster.
471
+ */
427
472
  function textIntern(doc, textBytes, optionen = {}) {
428
473
  const stile = vollstaendigeStile(optionen.styles);
429
474
  const colInd = optionen.colInd ?? 0;
430
475
  const colWidth = optionen.colWidth ?? 12;
431
- const breiteJeZeichen = zeichenBreite(doc, stile);
432
- let von = spaltenPosition(doc, colInd);
433
- if (colWidth !== 12) {
434
- const bis = spaltenPosition(doc, colInd + colWidth) - doc.spaceBetweenRows;
435
- const textLaenge = textBytes.length * breiteJeZeichen;
436
- if (stile.align === 'right') {
437
- von = bis - textLaenge;
438
- }
439
- else if (stile.align === 'center') {
440
- von = von + (bis - von) / 2 - textLaenge / 2;
476
+ const volleZeile = colInd === 0 && colWidth === 12;
477
+ // Bekommt die Spalte ohnehin eine von Hand berechnete Position (siehe
478
+ // unten), darf an den Drucker nur "links" gehen -- nie ihre eigentliche
479
+ // Ausrichtung. `ESC a` wirkt nicht auf die Spalte, sondern auf die ganze
480
+ // Zeile bis zum naechsten Zeilenumbruch: eine zentrierte oder rechts-
481
+ // buendige erste Spalte wuerde sonst den Drucker seine eigene Zentrierung
482
+ // auf jede weitere Spalte derselben Zeile anwenden lassen -- dieselbe
483
+ // Fehlerklasse wie der behobene Ausrichtungsfehler, eine Ebene tiefer.
484
+ // Die tatsaechliche Ausrichtung fliesst nur noch in die Positionsrechnung
485
+ // unten ein (ueber `stile`, nicht ueber diesen Befehl).
486
+ const stileFuerDrucker = colInd === 0 && !volleZeile ? { ...optionen.styles, align: 'left' } : optionen.styles;
487
+ // Ausrichtung vor Position -- `ESC a` gilt nur am Zeilenanfang, nach `ESC $`
488
+ // verwirft der Drucker ihn. Zwilling von `_text` in generator.dart.
489
+ escPosSetStyles(doc, stileFuerDrucker, { zeilenanfang: colInd === 0 });
490
+ // Eine volle Zeile beginnt am linken Rand; ein Positionsbefehl dafuer waere
491
+ // nicht nur ueberfluessig, er entwertet die Ausrichtung.
492
+ if (!volleZeile) {
493
+ const breiteJeZeichen = zeichenBreite(doc, stile);
494
+ let von = spaltenPosition(doc, colInd);
495
+ if (colWidth !== 12) {
496
+ const bis = spaltenPosition(doc, colInd + colWidth) - doc.spaceBetweenRows;
497
+ const textLaenge = textBytes.length * breiteJeZeichen;
498
+ if (stile.align === 'right') {
499
+ von = bis - textLaenge;
500
+ }
501
+ else if (stile.align === 'center') {
502
+ von = von + (bis - von) / 2 - textLaenge / 2;
503
+ }
504
+ if (von < 0)
505
+ von = 0;
441
506
  }
442
- if (von < 0)
443
- von = 0;
507
+ const position = runden(von);
508
+ anhaengen(doc, [...C_POS, position & 0xff, (position >> 8) & 0xff]);
444
509
  }
445
- const position = runden(von);
446
- anhaengen(doc, [...C_POS, position & 0xff, (position >> 8) & 0xff]);
447
- escPosSetStyles(doc, optionen.styles);
448
510
  anhaengen(doc, textBytes);
449
511
  }
450
512
  /**
@@ -681,13 +743,6 @@ export function escPosQrCode(doc, text, options = {}) {
681
743
  }
682
744
  if (drucken)
683
745
  anhaengen(doc, qrCodeBytes(text, qrOptionen));
684
- // Ausrichtung SOFORT zuruecksetzen: `ESC a` gilt nur am Zeilenanfang. Die
685
- // Spalten-Positionierung (`ESC $`) schickt ihren Reset sonst mitten in der
686
- // Zeile — Epson ignoriert ihn, und alles nach dem QR rueckte nach rechts
687
- // (belegt am TM-T20, 2026-08-20).
688
- if ((options.align ?? 'center') !== 'left') {
689
- escPosSetStyles(doc, { align: 'left' });
690
- }
691
746
  }
692
747
  /**
693
748
  * Der Bildweg: ein fertiges QR-Raster als Rasterbild (`GS v 0`) — der
@@ -745,9 +800,6 @@ export function escPosQrRaster(doc, matrix, options = {}) {
745
800
  anhaengen(doc, rasterBildKopf(breite, breite));
746
801
  anhaengen(doc, daten);
747
802
  anhaengen(doc, [ZEILENUMBRUCH]);
748
- if ((options.align ?? 'center') !== 'left') {
749
- escPosSetStyles(doc, { align: 'left' });
750
- }
751
803
  }
752
804
  /**
753
805
  * Punkte je Modul, mit denen `escPosQrRaster` ein Raster dieser Groesse auf
@@ -820,7 +872,4 @@ export function escPosRasterBild(doc, bild, options = {}) {
820
872
  escPosSetStyles(doc, { align: options.align ?? 'center' });
821
873
  anhaengen(doc, rasterBildKopf(bild.breite, bild.hoehe));
822
874
  anhaengen(doc, daten);
823
- if ((options.align ?? 'center') !== 'left') {
824
- escPosSetStyles(doc, { align: 'left' });
825
- }
826
875
  }
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
- import { belegBlatt, logoPixelZulaessig } from '../receipt/blatt.js';
3
+ import { belegBlatt, logoPixelZulaessig, PUNKTE_JE_ZEICHEN } from '../receipt/blatt.js';
4
+ import { MARKE_PFADE } from '../receipt/marke-daten.js';
4
5
  const AUSRICHTUNG = {
5
6
  left: 'left',
6
7
  center: 'center',
@@ -82,6 +83,11 @@ export function BelegBlattZeilen({ blatt, logoUrl, renderQr, qrVerdeckt = false,
82
83
  return (_jsx("div", { className: "keck-blatt-zeile", style: { whiteSpace: 'pre', height: '2ch', lineHeight: '2ch', overflow: 'hidden', fontWeight: b.fett ? 'bold' : 'normal' }, children: b.text }, i));
83
84
  case 'logo':
84
85
  return (_jsx("div", { className: "keck-blatt-logo", style: { height: `${b.hoeheZeilen * 2}ch`, display: 'flex', justifyContent: 'center' }, children: logoUrl === undefined ? null : (_jsx("img", { src: logoUrl, alt: "", "aria-hidden": "true", style: { width: `${b.breiteAnteil * z}ch`, height: `${b.hoeheZeilen * 2}ch`, objectFit: 'contain' } })) }, i));
86
+ case 'marke':
87
+ // Kein Rasterbild wie am Bon: Dieses Paket hat bewusst keine
88
+ // Abhaengigkeiten, und die Pfade liegen ohnehin schon vor (PDF
89
+ // zeichnet dieselben). Ein SVG bleibt in jeder Aufloesung scharf.
90
+ return (_jsx("div", { className: "keck-blatt-marke", style: { height: `${b.hoehe / PUNKTE_JE_ZEICHEN}ch`, display: 'flex', justifyContent: 'center' }, children: _jsx("svg", { viewBox: `0 0 ${MARKE_PFADE.breite} ${MARKE_PFADE.hoehe}`, width: `${b.breite / PUNKTE_JE_ZEICHEN}ch`, height: `${b.hoehe / PUNKTE_JE_ZEICHEN}ch`, role: "img", "aria-label": "Kasseneck", fill: "currentColor", children: MARKE_PFADE.pfade.map((d, j) => _jsx("path", { d: d }, j)) }) }, i));
85
91
  case 'qr': {
86
92
  // Auch beim Anteil 0 (leer oder in keine Version passend) bekommt
87
93
  // `renderQr` die Nutzlast: die Oberflaeche muss sagen koennen, dass
@@ -23,8 +23,6 @@ export declare const LOGO_STUFEN: Readonly<Record<LogoStufe, {
23
23
  }>>;
24
24
  export declare const PUNKTE_JE_ZEICHEN = 12;
25
25
  export declare const PUNKTE_JE_ZEILE = 24;
26
- /** Die Marke am Belegende (Konto-Flag `kreiseck_logo`) -- Text, damit jeder Weg sie gleich setzt. */
27
- export declare const MARKE_TEXT = "erstellt mit Kasseneck";
28
26
  export interface BlattLogo {
29
27
  stufe: LogoStufe;
30
28
  /** Pixelmass des Originalbilds -- ohne das laesst sich nicht einpassen. */
@@ -50,6 +48,10 @@ export type BlattBlock = {
50
48
  readonly art: 'qr';
51
49
  readonly nutzlast: string;
52
50
  readonly breiteAnteil: number;
51
+ } | {
52
+ readonly art: 'marke';
53
+ readonly breite: number;
54
+ readonly hoehe: number;
53
55
  };
54
56
  export interface BelegBlatt {
55
57
  readonly zeichen: number;
@@ -60,7 +62,7 @@ export interface BelegBlattOptionen {
60
62
  zeichen?: number;
61
63
  /** Firmenlogo; ohne Angabe kein Logo-Block. */
62
64
  logo?: BlattLogo | null;
63
- /** "erstellt mit Kasseneck" am Ende. */
65
+ /** Das Kasseneck-Logo am Ende (Konto-Flag `kreiseck_logo`). */
64
66
  marke?: boolean;
65
67
  /** Geraete-Einstellung fuer die QR-Modulgroesse; Vorgabe `auto` (hoechstens 6 Punkte je Modul) — wie die Druckwege. */
66
68
  qrGroesse?: QrModulGroesse;
@@ -1,5 +1,6 @@
1
1
  import { QR_DRUCK_PUNKTE, QR_RUHEZONE_MODULE, qrGroesseFuer, qrPasstInVersion, qrRasterPunkte, } from '../printing/index.js';
2
2
  import { renderReceiptGrid, ZEICHEN_JE_PAPIER } from './grid.js';
3
+ import { MARKE_RASTER } from './marke-daten.js';
3
4
  /** Kasten je Stufe: Anteil der Blattbreite und Hoehe in Zeilen (Werte der Web-Kasse). */
4
5
  export const LOGO_STUFEN = {
5
6
  S: { breiteAnteil: 0.42, hoeheZeilen: 5 },
@@ -9,8 +10,6 @@ export const LOGO_STUFEN = {
9
10
  };
10
11
  export const PUNKTE_JE_ZEICHEN = 12;
11
12
  export const PUNKTE_JE_ZEILE = 24;
12
- /** Die Marke am Belegende (Konto-Flag `kreiseck_logo`) -- Text, damit jeder Weg sie gleich setzt. */
13
- export const MARKE_TEXT = 'erstellt mit Kasseneck';
14
13
  /**
15
14
  * 32 Zeichen sind 58 mm, 48 sind 80 mm; andere Breiten behalten das Papier des
16
15
  * Layouts. Der QR-Anteil (`qrBlattAnteil`) wird dann fuer die Kopfbreite
@@ -88,11 +87,6 @@ export function qrBlattAnteil(nutzlast, papier, groesse = 'auto') {
88
87
  return mass.breitePunkte / papierPunkte;
89
88
  return ((mass.module + 2 * QR_RUHEZONE_MODULE) * qrRasterPunkte(papier, mass.module, { groesse })) / papierPunkte;
90
89
  }
91
- function zentriert(text, zeichen) {
92
- const t = text.length > zeichen ? text.slice(0, zeichen) : text;
93
- const links = Math.floor((zeichen - t.length) / 2);
94
- return ' '.repeat(links) + t + ' '.repeat(zeichen - t.length - links);
95
- }
96
90
  export function belegBlatt(layout, optionen = {}) {
97
91
  const grid = renderReceiptGrid(layout, optionen.zeichen === undefined ? {} : { zeichen: optionen.zeichen });
98
92
  const zeichen = grid.zeichen;
@@ -121,8 +115,15 @@ export function belegBlatt(layout, optionen = {}) {
121
115
  for (; i < grid.lines.length; i += 1)
122
116
  bloecke.push(block(grid.lines[i]));
123
117
  if (optionen.marke === true) {
124
- bloecke.push(leerzeile);
125
- bloecke.push({ art: 'zeile', text: zentriert(MARKE_TEXT, zeichen), fett: false, leer: false });
118
+ // Das Raster deckt nur die beiden bekannten Papierbreiten ab (`MARKE_RASTER`).
119
+ // Faende sich hier eine dritte, faellt die Marke weg statt ein Raster in
120
+ // falscher Groesse zu drucken -- derselbe Grundsatz wie beim Firmenlogo:
121
+ // eine Marke ist Zierde, der Beleg ist Pflicht.
122
+ const raster = MARKE_RASTER[papier];
123
+ if (raster) {
124
+ bloecke.push(leerzeile);
125
+ bloecke.push({ art: 'marke', breite: raster.breite, hoehe: raster.hoehe });
126
+ }
126
127
  }
127
128
  return { zeichen, bloecke };
128
129
  }
@@ -35,7 +35,7 @@ export interface EposPrintXmlOptions {
35
35
  cut?: boolean;
36
36
  /** Firmenlogo; ohne Angabe kein Logo. */
37
37
  logo?: DruckLogo | null;
38
- /** "erstellt mit Kasseneck" am Ende. */
38
+ /** Das Kasseneck-Logo am Ende (Konto-Flag `kreiseck_logo`). */
39
39
  marke?: boolean;
40
40
  }
41
41
  /**
@@ -86,7 +86,7 @@ export interface EposDirectOptions {
86
86
  qrGroesse?: QrModulGroesse;
87
87
  /** Firmenlogo; ohne Angabe kein Logo. */
88
88
  logo?: DruckLogo | null;
89
- /** "erstellt mit Kasseneck" am Ende. */
89
+ /** Das Kasseneck-Logo am Ende (Konto-Flag `kreiseck_logo`). */
90
90
  marke?: boolean;
91
91
  timeoutMs?: number;
92
92
  }
@@ -1,6 +1,8 @@
1
1
  import { QR_DRUCK_PUNKTE, QR_MINDEST_PUNKTE, QR_MODUL_DECKEL, qrGroesseFuer, qrPasstInVersion, rasterZeilenBase64, } from '../printing/index.js';
2
2
  import { ZEICHEN_JE_PAPIER } from './grid.js';
3
+ import { papierFuerZeichen } from './blatt.js';
3
4
  import { blattFuerDruck } from './layout-escpos.js';
5
+ import { markeBild } from './marke.js';
4
6
  export function eposXmlEscape(text) {
5
7
  return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;');
6
8
  }
@@ -25,6 +27,7 @@ export function eposPrintXml(layout, options = {}) {
25
27
  */
26
28
  export function eposPrintXmlErgebnis(layout, options = {}) {
27
29
  const zeichen = options.zeichen ?? ZEICHEN_JE_PAPIER[layout.paperSize];
30
+ const papier = papierFuerZeichen(zeichen, layout.paperSize);
28
31
  const deckel = options.qrGroesse ?? 'auto';
29
32
  const blatt = blattFuerDruck(layout, { zeichen, logo: options.logo, marke: options.marke, qrGroesse: deckel });
30
33
  const fest = options.qrBreite === undefined
@@ -94,6 +97,11 @@ export function eposPrintXmlErgebnis(layout, options = {}) {
94
97
  out.push('<text align="left"/>');
95
98
  }
96
99
  break;
100
+ case 'marke':
101
+ out.push('<text align="center"/>');
102
+ out.push(eposBildXml(markeBild(papier)));
103
+ out.push('<text align="left"/>');
104
+ break;
97
105
  case 'qr': {
98
106
  const breite = qrBreiteFuer(block.nutzlast);
99
107
  if (breite === null)
@@ -2,5 +2,7 @@ export { type LayoutAlign, type LayoutColumn, type LayoutTextLine, type LayoutCo
2
2
  export { type EscPosLayoutOptions, type EscPosLayoutErgebnis, type QrPrintMode, type DruckLogo, pruefeLogoRaster, escPosLayoutBytes, escPosLayoutErgebnis, } from './layout-escpos.js';
3
3
  export { type GridLine, type GridLineKind, type ReceiptGrid, type RenderReceiptGridOptions, renderReceiptGrid, gridSpaltenBreiten, gridAlsText, ZEICHEN_JE_PAPIER, } from './grid.js';
4
4
  export { type EposPrintXmlOptions, type EposPrintErgebnis, type EposDirectOptions, type EposResponse, EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposBildXml, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
5
- export { type LogoStufe, type BlattLogo, type LogoMass, type BlattBlock, type BelegBlatt, type BelegBlattOptionen, LOGO_STUFEN, LOGO_PIXEL_MAX, PUNKTE_JE_ZEICHEN, PUNKTE_JE_ZEILE, MARKE_TEXT, papierFuerZeichen, logoMass, logoPixelZulaessig, logoRasterMass, qrBlattAnteil, belegBlatt, } from './blatt.js';
5
+ export { type LogoStufe, type BlattLogo, type LogoMass, type BlattBlock, type BelegBlatt, type BelegBlattOptionen, LOGO_STUFEN, LOGO_PIXEL_MAX, PUNKTE_JE_ZEICHEN, PUNKTE_JE_ZEILE, papierFuerZeichen, logoMass, logoPixelZulaessig, logoRasterMass, qrBlattAnteil, belegBlatt, } from './blatt.js';
6
6
  export { logoRaster } from './bild.js';
7
+ export { type MarkeRasterDaten, MARKE_RASTER, MARKE_PFADE } from './marke-daten.js';
8
+ export { markeBild } from './marke.js';
@@ -2,5 +2,7 @@ export { buildReceiptLayout, receiptSignatureFailed, receiptSignatureIsTest, rec
2
2
  export { pruefeLogoRaster, escPosLayoutBytes, escPosLayoutErgebnis, } from './layout-escpos.js';
3
3
  export { renderReceiptGrid, gridSpaltenBreiten, gridAlsText, ZEICHEN_JE_PAPIER, } from './grid.js';
4
4
  export { EposConnectionError, eposPrintXml, eposPrintXmlErgebnis, eposXmlEscape, eposBildXml, eposServiceUrl, eposSoapEnvelope, eposParseResponse, eposDirectPrint, eposDirectStatus } from './epos.js';
5
- export { LOGO_STUFEN, LOGO_PIXEL_MAX, PUNKTE_JE_ZEICHEN, PUNKTE_JE_ZEILE, MARKE_TEXT, papierFuerZeichen, logoMass, logoPixelZulaessig, logoRasterMass, qrBlattAnteil, belegBlatt, } from './blatt.js';
5
+ export { LOGO_STUFEN, LOGO_PIXEL_MAX, PUNKTE_JE_ZEICHEN, PUNKTE_JE_ZEILE, papierFuerZeichen, logoMass, logoPixelZulaessig, logoRasterMass, qrBlattAnteil, belegBlatt, } from './blatt.js';
6
6
  export { logoRaster } from './bild.js';
7
+ export { MARKE_RASTER, MARKE_PFADE } from './marke-daten.js';
8
+ export { markeBild } from './marke.js';
@@ -80,7 +80,7 @@ export interface EscPosLayoutOptions {
80
80
  qrMatrix?: (nutzlast: string) => QrMatrix;
81
81
  /** Firmenlogo; ohne Angabe kein Logo (Bestand). */
82
82
  logo?: DruckLogo | null;
83
- /** "erstellt mit Kasseneck" am Ende (Konto-Flag `kreiseck_logo`). */
83
+ /** Das Kasseneck-Logo am Ende (Konto-Flag `kreiseck_logo`). */
84
84
  marke?: boolean;
85
85
  }
86
86
  /**
@@ -1,6 +1,7 @@
1
1
  import { createEscPosDocument, escPosBytes, escPosCut, escPosFeed, escPosPrintableText, escPosQrCode, escPosQrRaster, escPosRasterBild, escPosReset, escPosText, QR_DRUCK_PUNKTE, qrGroesseFuer, qrPasstInVersion, } from '../printing/index.js';
2
2
  import { belegBlatt, logoRasterMass } from './blatt.js';
3
3
  import { ZEICHEN_JE_PAPIER } from './grid.js';
4
+ import { markeBild } from './marke.js';
4
5
  /** Das Rasterbild muss genau so gross sein, wie das Blatt das Logo setzt -- sonst stuende am Bon ein anderes Logo als am Schirm. */
5
6
  export function pruefeLogoRaster(logo, mass, zeichen) {
6
7
  const soll = logoRasterMass(mass, zeichen);
@@ -148,6 +149,9 @@ export function escPosLayoutErgebnis(layout, options = {}) {
148
149
  if (options.logo)
149
150
  escPosRasterBild(doc, options.logo.raster, { align: 'center' });
150
151
  break;
152
+ case 'marke':
153
+ escPosRasterBild(doc, markeBild(paperSize), { align: 'center' });
154
+ break;
151
155
  case 'zeile':
152
156
  if (block.leer)
153
157
  escPosFeed(doc, 1);
@@ -0,0 +1,14 @@
1
+ import type { PosPaperSize } from '../printing/escpos.js';
2
+ export interface MarkeRasterDaten {
3
+ readonly breite: number;
4
+ readonly hoehe: number;
5
+ /** Rasterzeilen als Bits, MSB zuerst, je Zeile auf volle Bytes aufgefuellt; base64. */
6
+ readonly bits: string;
7
+ }
8
+ export declare const MARKE_RASTER: Readonly<Record<PosPaperSize, MarkeRasterDaten>>;
9
+ /** Die Marke als Pfade (fuer PDF und Bildschirm), im Kasten der Markendatei. */
10
+ export declare const MARKE_PFADE: {
11
+ readonly breite: number;
12
+ readonly hoehe: number;
13
+ readonly pfade: readonly string[];
14
+ };
@@ -0,0 +1,15 @@
1
+ export const MARKE_RASTER = {
2
+ mm80: { breite: 352, hoehe: 51, bits: "////////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAA////////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf4AAD+AAAAAAfgAAAD+AAH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAP4AAAAAB+AAAAf4AA/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH+AAA/gAAAAAH4AAAB/gAH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf4AAD+AAAAAAfgAAAH+AAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAP4AAAAAB+AAAAf4AD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH+AAA/gAAAAAH4AAAB/gAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf4AAD+AAAAAAfgAAAH+AD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAP4AAAAAB+AAAAf4Af8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH+AAA/gAAAAAH4AAAB/gD/gAAPgAAAHgAAAHgAAAPgAAAAeAAAB8AAAB8AAf4AAD+AAAAAAfgAAAH+Af8AAP/4AAP/8AAP/4AAP/4AH4P/AAB//AAB//AB/gB/v4AAAAAB+AAAAf4D/gAD//4AD//8AD//4AD//4Afj//AAf//AAP//AH+AP8/gAAAAAH4AAAB/gf8AAf//wAf//4Af//wAf//wB+f/+AD//+AD//+Af4B/j+AAAAAAfgAAAH+D/gAD///gD///wD///gD///gH///4Af//8Af//8B/gP8P4AAAAAB+AAAAf4f8AAf///Af///Af///Af///Af///wD///4B///4H+B/g/gAAAAAH4AAAB/j/gAB/gf8B/wP+D/gf8B/wP8B////Af+D/gP/D/wf4P+D+AAAAAAfgAAAH+f8AAH8AfwH8Af4P8Af4P8Af4H/gP+B/gD/A/wD/B/g/wP4AAAAAB+AAAAf7/wAA/wB/A/wA/g/gA/g/wA/gf8Af4P8AP8H+AH8H+H+A/gAAAAAH4AAAB///gAB+AH8D/AD+D+AD+D+AD/B/gB/g/wAfwfwAfwf4/wD+AAAAAAfgAAAH///AAAAAf4P+AAAP8AAAf4AH8H+AD+D+AB/B/AB/h/n+AP4AAAAAB+AAAAf//8AAAAB/gf+AAA/8AAB/AAfwfwAP4P4AH+P8AH+H+/wA/gAAAAAH4AAAB///4AAAAH+B//AAB//AAH+AD/B/AA/g/gAf4/wAAAf//AD+AAAAAAfgAAAH///wAAD//4D//wAH//gAf///8H8AD+D////j+AAAB//8AP4AAAAAB+AAAAf/j/AAB///gP//4AP//wB////wfwAP4f///+P4AAAH//wA/gAAAAAH4AAAB/8P+AAf//+AP//4Af//wH////B/AA/h////4/gAAAf//gD+AAAAAA/gAAAH/gf8AD///4Af//wAf//gf///8H8AD+H////j+AAAB///AP4AAAD//+AAAAf8A/wAf///gAP//gAf//B////wfwAP4f///+P4AAAH//8A/gAAAP//4AAAB/gD/gD/wH+AAH/+AAH/+H8AAAB/AA/g/gAAA/gAAAf/f4D+AAAA///gAAAH+AH/AP8Af4AAB/8AAD/4fwAAAH8AD+D+AAAD/AAAB/4/gP4AAAD//+AAAAf4AP8B/gB/gAAB/wAAB/h/AAfwfwAP4P4AD8P8AD+H/D/A/gAAAP//4AAAB/gA/4H8AH+D8AD/D8AD/H+AB/B/AA/g/gAP4fwAP4f4H8D+AAAA///gAAAH+AB/wfwAf4P4AH8fwAP8P4AH8H8AD+D/AB/h/AB/B/gf4P4AAAD//+AAAAf4AD/B/AD/g/gAfx/gA/g/wA/wfwAP4H8AH8H+AH8H+A/w/gAAAP//4AAAB/gAP+H+Af+D/AD/D/AD+D/AH+B/AA/gf4A/wP8A/wf4D/D+AAAA///gAAAH+AAf8f+P/8P/A/4P/A/4H/A/4H8AD+B/4P/A/8P+B/gH+P4AAAD//+AAAAf4AA/w////8f///g////Af///AfwAP4D///4B///4H+Af4/gAAAP//4AAAB/gAD/j////w///8B///8A///8B/AA/gH///AH///Af4A/z+AAAA///gAAAH+AAH/H//n/B///gD///gB///gH8AD+AP//4AP//4B/gD/P4AAAH//+AAAAf4AAf8P/8f8D//8AD//8AB//4AfwAP4Af//AAP//AH+AH+////////4AAAA/gAA/4f/A/wD//AAD/+AAB/+AB/AA/gAf/wAAP/wAPwAP7////////gAAAAAAAAAAHAAAAAeAAAAcAAAAeAAAAAAAAADgAAADgAAAAAAP///////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" },
3
+ mm58: { breite: 234, hoehe: 34, bits: "/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAA+AAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAA8AAAA8AAHwAfgAAAAAAAAAAAAAAAAAAAAAAA+AAA8AAAA8AAHwA/AAAAAAAAAAAAAAAAAAAAAAAA+AAA8AAAA8AAHwB+AAAAAAAAAAAAAAAAAAAAAAAA+AAA8AAAA8AAHwD8AAAAAAAAAAAAAAAAAAAAAAAA+AAA8AAAA8AAHwH4AAAAAAAAAAAAAAAAAAAAAAAA+AAA8AAAA8AAHwPwAPwAD8AA+AAPwAAfAAPgAD4A+AAA8AAAA8AAHwfgB/8AP/AH/wB/8B5/wB/8Af/A+B+A8AAAA8AAHw/AD/+A//wP/4D/+B7/4D/+A//g+D8A8AAAA8AAHx+AH//B//4f/8H//B//4H//B//w+D4A8AAAA8AAHz+AHwfB8H4fB+H4fh/n8PwfB+P4+HwA8AAAA8AAH/8AHwPh8D4+A+PgPh+B8PgPj8D4+PgA8AAAA8AAH/+AHgPh8B4+AcPgPh8B8PgPj4D4+fgA8AAAA8AAH/+AAAPh+AA/gAPgHh8B8fAPj4D4+/AA8AAAA8AAH//AAA/h/4Af8AP//x8B8f//jwAA/+AA8AAAA8AAH/fgA//g//Af/gf//x8B8f//jwAA//AA8AAAA8AAH8PgD//gf/wH/4f//x8B8f//nwAA//AA8AAD/8AAH4PwH//gH/4B/8f//x8B8f//nwAA//gA8AAH/8AAH4H4P4PgA/4AP+PAAB8B8fAADwAA/vgA8AAH/8AAHwH4PgPgAD8AB+PgCh8B8fAAD4B4/HwA8AAH/8AAHwD8PgPj4B88A+PgHx8B8fAHj4D4+HwA8AAH/8AAHwB+Pgfj4B8+A+PgHh8B8PgPj4D4+D4A8AAH/8AAHwB+Pg/j8D4/A+HwPh8B8Pwfh8H4+D8A8AAH/8AAHwA/P//5//4f/+H//h8B8H//B//w+B8A8AAH/8AAHwAfn//4//wf/8D//B8B8D//A//g+B+A+AAH/8AAHwAfn/n4f/gP/4B/+B8B8B/8Af/A+A+A/////8AADwAPh+D4H+AB/gAf4B4A8AfwAH8AeAeA/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" },
4
+ };
5
+ /** Die Marke als Pfade (fuer PDF und Bildschirm), im Kasten der Markendatei. */
6
+ export const MARKE_PFADE = {
7
+ breite: 332,
8
+ hoehe: 48,
9
+ pfade: [
10
+ "M0 0H48V30H42V6H0Z",
11
+ "M0 6V48H30V42H6V6Z",
12
+ "M30 30H48V48H30Z",
13
+ "M73.028 43V6.642H79.918V23.496L96.03 6.642H104.457L90.359 21.376L104.722 43H96.56L85.695 26.199L79.918 31.287V43Z M113.515 43.636Q112.349 43.636 110.838 43.344Q109.328 43.053 107.923 42.258Q106.519 41.463 105.618 39.9Q104.717 38.336 104.717 35.792Q104.717 32.93 105.989 31.049Q107.261 29.167 109.566 28.081Q111.872 26.994 115.078 26.544Q118.285 26.093 122.101 26.093V23.814Q122.101 22.595 121.73 21.641Q121.359 20.687 120.379 20.131Q119.398 19.574 117.437 19.574Q115.476 19.574 114.363 20.051Q113.25 20.528 112.826 21.217Q112.402 21.906 112.402 22.648V23.39H106.148Q106.095 23.125 106.095 22.86Q106.095 22.595 106.095 22.224Q106.095 19.839 107.526 18.09Q108.957 16.341 111.501 15.414Q114.045 14.486 117.384 14.486Q121.2 14.486 123.664 15.546Q126.129 16.606 127.348 18.567Q128.567 20.528 128.567 23.337V36.481Q128.567 37.488 129.15 37.912Q129.733 38.336 130.422 38.336H132.118V42.788Q131.588 43 130.581 43.291Q129.574 43.583 128.09 43.583Q126.712 43.583 125.625 43.133Q124.539 42.682 123.797 41.834Q123.055 40.986 122.737 39.82H122.419Q121.518 40.933 120.272 41.808Q119.027 42.682 117.357 43.159Q115.688 43.636 113.515 43.636ZM115.476 38.336Q117.066 38.336 118.311 37.859Q119.557 37.382 120.378 36.534Q121.2 35.686 121.65 34.467Q122.101 33.248 122.101 31.817V30.545Q119.186 30.545 116.721 30.916Q114.257 31.287 112.799 32.294Q111.342 33.301 111.342 35.156Q111.342 36.11 111.792 36.825Q112.243 37.541 113.17 37.938Q114.098 38.336 115.476 38.336Z M145.893 43.636Q142.872 43.636 140.593 42.974Q138.314 42.311 136.777 41.145Q135.24 39.979 134.471 38.416Q133.703 36.852 133.703 34.997Q133.703 34.732 133.73 34.52Q133.756 34.308 133.756 34.202H140.116Q140.116 34.308 140.116 34.414Q140.116 34.52 140.116 34.626Q140.169 36.057 141.017 36.931Q141.865 37.806 143.243 38.177Q144.621 38.548 146.158 38.548Q147.536 38.548 148.781 38.257Q150.027 37.965 150.849 37.303Q151.67 36.64 151.67 35.58Q151.67 34.202 150.61 33.46Q149.55 32.718 147.827 32.241Q146.105 31.764 144.144 31.234Q142.395 30.757 140.646 30.174Q138.897 29.591 137.493 28.69Q136.088 27.789 135.214 26.358Q134.339 24.927 134.339 22.807Q134.339 20.74 135.24 19.203Q136.141 17.666 137.731 16.633Q139.321 15.599 141.494 15.069Q143.667 14.539 146.211 14.539Q148.702 14.539 150.743 15.069Q152.783 15.599 154.293 16.58Q155.804 17.56 156.625 18.965Q157.447 20.369 157.447 22.065Q157.447 22.436 157.421 22.807Q157.394 23.178 157.394 23.231H151.087V22.86Q151.087 21.853 150.477 21.138Q149.868 20.422 148.728 19.998Q147.589 19.574 145.893 19.574Q144.621 19.574 143.667 19.786Q142.713 19.998 142.103 20.369Q141.494 20.74 141.176 21.217Q140.858 21.694 140.858 22.277Q140.858 23.284 141.653 23.867Q142.448 24.45 143.8 24.874Q145.151 25.298 146.741 25.775Q148.649 26.305 150.663 26.861Q152.677 27.418 154.399 28.266Q156.122 29.114 157.182 30.651Q158.242 32.188 158.242 34.732Q158.242 37.17 157.315 38.892Q156.387 40.615 154.718 41.648Q153.048 42.682 150.796 43.159Q148.543 43.636 145.893 43.636Z M173.766 43.636Q170.745 43.636 168.466 42.974Q166.187 42.311 164.65 41.145Q163.113 39.979 162.345 38.416Q161.576 36.852 161.576 34.997Q161.576 34.732 161.603 34.52Q161.629 34.308 161.629 34.202H167.989Q167.989 34.308 167.989 34.414Q167.989 34.52 167.989 34.626Q168.042 36.057 168.89 36.931Q169.738 37.806 171.116 38.177Q172.494 38.548 174.031 38.548Q175.409 38.548 176.655 38.257Q177.9 37.965 178.721 37.303Q179.543 36.64 179.543 35.58Q179.543 34.202 178.483 33.46Q177.423 32.718 175.701 32.241Q173.978 31.764 172.017 31.234Q170.268 30.757 168.519 30.174Q166.77 29.591 165.365 28.69Q163.961 27.789 163.087 26.358Q162.212 24.927 162.212 22.807Q162.212 20.74 163.113 19.203Q164.014 17.666 165.604 16.633Q167.194 15.599 169.367 15.069Q171.54 14.539 174.084 14.539Q176.575 14.539 178.615 15.069Q180.656 15.599 182.167 16.58Q183.677 17.56 184.499 18.965Q185.32 20.369 185.32 22.065Q185.32 22.436 185.294 22.807Q185.267 23.178 185.267 23.231H178.96V22.86Q178.96 21.853 178.351 21.138Q177.741 20.422 176.602 19.998Q175.462 19.574 173.766 19.574Q172.494 19.574 171.54 19.786Q170.586 19.998 169.977 20.369Q169.367 20.74 169.049 21.217Q168.731 21.694 168.731 22.277Q168.731 23.284 169.526 23.867Q170.321 24.45 171.673 24.874Q173.024 25.298 174.614 25.775Q176.522 26.305 178.536 26.861Q180.55 27.418 182.273 28.266Q183.995 29.114 185.055 30.651Q186.115 32.188 186.115 34.732Q186.115 37.17 185.188 38.892Q184.26 40.615 182.591 41.648Q180.921 42.682 178.669 43.159Q176.416 43.636 173.766 43.636Z M202.752 43.636Q198.3 43.636 195.332 42.073Q192.364 40.509 190.88 37.276Q189.396 34.043 189.396 29.061Q189.396 24.026 190.88 20.819Q192.364 17.613 195.332 16.05Q198.3 14.486 202.752 14.486Q206.78 14.486 209.51 15.997Q212.239 17.507 213.617 20.634Q214.995 23.761 214.995 28.743V30.651H196.021Q196.127 33.248 196.816 35.023Q197.505 36.799 198.963 37.674Q200.42 38.548 202.805 38.548Q204.024 38.548 205.084 38.23Q206.144 37.912 206.939 37.249Q207.734 36.587 208.185 35.58Q208.635 34.573 208.635 33.248H214.995Q214.995 35.898 214.067 37.859Q213.14 39.82 211.471 41.092Q209.801 42.364 207.575 43Q205.349 43.636 202.752 43.636ZM196.127 26.093H208.264Q208.264 24.344 207.867 23.125Q207.469 21.906 206.754 21.111Q206.038 20.316 205.031 19.971Q204.024 19.627 202.752 19.627Q200.685 19.627 199.281 20.316Q197.876 21.005 197.134 22.436Q196.392 23.867 196.127 26.093Z M219.707 43V15.122H225.113L225.643 18.832H226.014Q226.968 17.56 228.266 16.58Q229.565 15.599 231.234 15.043Q232.904 14.486 234.918 14.486Q237.568 14.486 239.608 15.44Q241.649 16.394 242.815 18.514Q243.981 20.634 243.981 24.185V43H237.462V25.351Q237.462 23.867 237.117 22.887Q236.773 21.906 236.11 21.297Q235.448 20.687 234.494 20.422Q233.54 20.157 232.374 20.157Q230.625 20.157 229.22 21.005Q227.816 21.853 226.994 23.337Q226.173 24.821 226.173 26.782V43Z M261.837 43.636Q257.385 43.636 254.417 42.073Q251.449 40.509 249.965 37.276Q248.481 34.043 248.481 29.061Q248.481 24.026 249.965 20.819Q251.449 17.613 254.417 16.05Q257.385 14.486 261.837 14.486Q265.865 14.486 268.594 15.997Q271.324 17.507 272.702 20.634Q274.08 23.761 274.08 28.743V30.651H255.106Q255.212 33.248 255.901 35.023Q256.59 36.799 258.047 37.674Q259.505 38.548 261.89 38.548Q263.109 38.548 264.169 38.23Q265.229 37.912 266.024 37.249Q266.819 36.587 267.269 35.58Q267.72 34.573 267.72 33.248H274.08Q274.08 35.898 273.152 37.859Q272.225 39.82 270.555 41.092Q268.886 42.364 266.66 43Q264.434 43.636 261.837 43.636ZM255.212 26.093H267.349Q267.349 24.344 266.951 23.125Q266.554 21.906 265.838 21.111Q265.123 20.316 264.116 19.971Q263.109 19.627 261.837 19.627Q259.77 19.627 258.365 20.316Q256.961 21.005 256.219 22.436Q255.477 23.867 255.212 26.093Z M290.399 43.636Q286.053 43.636 283.164 42.073Q280.276 40.509 278.845 37.276Q277.414 34.043 277.414 29.061Q277.414 24.026 278.871 20.819Q280.329 17.613 283.217 16.05Q286.106 14.486 290.399 14.486Q293.208 14.486 295.381 15.175Q297.554 15.864 299.117 17.269Q300.681 18.673 301.476 20.74Q302.271 22.807 302.271 25.563H295.699Q295.699 23.602 295.116 22.33Q294.533 21.058 293.34 20.395Q292.148 19.733 290.293 19.733Q288.12 19.733 286.742 20.74Q285.364 21.747 284.702 23.735Q284.039 25.722 284.039 28.743V29.432Q284.039 32.4 284.702 34.414Q285.364 36.428 286.795 37.409Q288.226 38.389 290.558 38.389Q292.36 38.389 293.553 37.727Q294.745 37.064 295.381 35.739Q296.017 34.414 296.017 32.559H302.271Q302.271 35.156 301.476 37.223Q300.681 39.29 299.144 40.721Q297.607 42.152 295.407 42.894Q293.208 43.636 290.399 43.636Z M306.983 43V4.681H313.449V26.994L323.466 15.122H331.045L321.717 25.934L331.575 43H324.155L317.583 30.651L313.449 34.626V43Z"
14
+ ],
15
+ };
@@ -0,0 +1,20 @@
1
+ import type { PosPaperSize, RasterBild } from '../printing/escpos.js';
2
+ /**
3
+ * Entpackt gepackte Rasterzeilen (Base64, MSB zuerst, je Zeile auf volle Bytes
4
+ * aufgefuellt -- die Form von [rasterZeilenBytes]) in ein Punkt-je-Byte-Bild.
5
+ *
6
+ * Eigene, exportierte Funktion statt Code inline in `markeBild`: ein
7
+ * Rundlauf-Test (packen mit `rasterZeilenBytes`, entpacken hiermit) kann so
8
+ * denselben Entpacker pruefen, den die Marke zur Laufzeit auch benutzt --
9
+ * ein vertauschter Bit-Index waere sonst nur am schiefen Ausdruck sichtbar.
10
+ */
11
+ export declare function entpackeRasterBits(bits: string, breite: number, hoehe: number): RasterBild;
12
+ /**
13
+ * Die Marke als Rasterbild fuer diese Papierbreite.
14
+ *
15
+ * Entpackt die gepackten Zeilen in ein Punkt-je-Byte-Bild, wie es
16
+ * [escPosRasterBild] erwartet. Zur Laufzeit wird nichts gerechnet und nichts
17
+ * skaliert -- die beiden Masse stehen fest, damit JS und Dart fuer denselben
18
+ * Beleg dieselben Bytes erzeugen.
19
+ */
20
+ export declare function markeBild(paperSize: PosPaperSize): RasterBild;
@@ -0,0 +1,42 @@
1
+ import { MARKE_RASTER } from './marke-daten.js';
2
+ /** Base64 -> Bytes ohne `Buffer` -- laeuft im Browser und in Node gleich (wie `rasterZeilenBase64`). */
3
+ function base64Bytes(base64) {
4
+ const binaer = atob(base64);
5
+ const bytes = new Uint8Array(binaer.length);
6
+ for (let i = 0; i < binaer.length; i++)
7
+ bytes[i] = binaer.charCodeAt(i);
8
+ return bytes;
9
+ }
10
+ /**
11
+ * Entpackt gepackte Rasterzeilen (Base64, MSB zuerst, je Zeile auf volle Bytes
12
+ * aufgefuellt -- die Form von [rasterZeilenBytes]) in ein Punkt-je-Byte-Bild.
13
+ *
14
+ * Eigene, exportierte Funktion statt Code inline in `markeBild`: ein
15
+ * Rundlauf-Test (packen mit `rasterZeilenBytes`, entpacken hiermit) kann so
16
+ * denselben Entpacker pruefen, den die Marke zur Laufzeit auch benutzt --
17
+ * ein vertauschter Bit-Index waere sonst nur am schiefen Ausdruck sichtbar.
18
+ */
19
+ export function entpackeRasterBits(bits, breite, hoehe) {
20
+ const byteJeZeile = Math.ceil(breite / 8);
21
+ const roh = base64Bytes(bits);
22
+ const punkte = new Uint8Array(breite * hoehe);
23
+ for (let y = 0; y < hoehe; y++) {
24
+ for (let x = 0; x < breite; x++) {
25
+ const byte = roh[y * byteJeZeile + (x >> 3)];
26
+ punkte[y * breite + x] = (byte >> (7 - (x & 7))) & 1;
27
+ }
28
+ }
29
+ return { breite, hoehe, punkte };
30
+ }
31
+ /**
32
+ * Die Marke als Rasterbild fuer diese Papierbreite.
33
+ *
34
+ * Entpackt die gepackten Zeilen in ein Punkt-je-Byte-Bild, wie es
35
+ * [escPosRasterBild] erwartet. Zur Laufzeit wird nichts gerechnet und nichts
36
+ * skaliert -- die beiden Masse stehen fest, damit JS und Dart fuer denselben
37
+ * Beleg dieselben Bytes erzeugen.
38
+ */
39
+ export function markeBild(paperSize) {
40
+ const d = MARKE_RASTER[paperSize];
41
+ return entpackeRasterBits(d.bits, d.breite, d.hoehe);
42
+ }
@@ -150,10 +150,9 @@
150
150
  "leer": true
151
151
  },
152
152
  {
153
- "art": "zeile",
154
- "text": " erstellt mit Kasseneck ",
155
- "fett": false,
156
- "leer": false
153
+ "art": "marke",
154
+ "breite": 234,
155
+ "hoehe": 34
157
156
  }
158
157
  ]
159
158
  }