@kreiseck/kasseneck-api 0.10.0 → 0.12.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.
- package/CHANGELOG.md +94 -1
- package/README.md +41 -0
- package/dist/cjs/client/receipts.d.ts +8 -0
- package/dist/cjs/client/receipts.js +18 -0
- package/dist/cjs/printing/escpos.d.ts +85 -1
- package/dist/cjs/printing/escpos.js +140 -4
- package/dist/cjs/printing/index.d.ts +2 -1
- package/dist/cjs/printing/index.js +13 -1
- package/dist/cjs/printing/qr-groesse.d.ts +122 -0
- package/dist/cjs/printing/qr-groesse.js +126 -0
- package/dist/cjs/receipt/epos.d.ts +42 -1
- package/dist/cjs/receipt/epos.js +66 -5
- package/dist/cjs/receipt/index.d.ts +2 -2
- package/dist/cjs/receipt/index.js +3 -1
- package/dist/cjs/receipt/layout-escpos.d.ts +50 -2
- package/dist/cjs/receipt/layout-escpos.js +59 -2
- package/dist/esm/client/receipts.d.ts +8 -0
- package/dist/esm/client/receipts.js +18 -0
- package/dist/esm/printing/escpos.d.ts +85 -1
- package/dist/esm/printing/escpos.js +138 -4
- package/dist/esm/printing/index.d.ts +2 -1
- package/dist/esm/printing/index.js +2 -1
- package/dist/esm/printing/qr-groesse.d.ts +122 -0
- package/dist/esm/printing/qr-groesse.js +120 -0
- package/dist/esm/receipt/epos.d.ts +42 -1
- package/dist/esm/receipt/epos.js +65 -5
- package/dist/esm/receipt/index.d.ts +2 -2
- package/dist/esm/receipt/index.js +2 -2
- package/dist/esm/receipt/layout-escpos.d.ts +50 -2
- package/dist/esm/receipt/layout-escpos.js +59 -3
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/kasse-texte.json +1 -1
- package/fixtures/oberflaeche.json +1 -1
- package/package.json +1 -1
|
@@ -140,6 +140,24 @@ export async function cancelReceipt(rufen, options) {
|
|
|
140
140
|
params.note = options.note;
|
|
141
141
|
if (options.paymentMethod != null)
|
|
142
142
|
params.paymentMethod = gepruefteZahlungsart(options.paymentMethod);
|
|
143
|
+
const karte = options.creditCardProvider != null || options.cardPaymentId != null || options.cardPaymentData != null;
|
|
144
|
+
if (karte) {
|
|
145
|
+
// Ohne paymentMethod entscheidet das Backend an der Zahlungsart des
|
|
146
|
+
// Originals; ein ausdruecklich anderer Rueckzahlweg ist hier schon falsch.
|
|
147
|
+
if (params.paymentMethod != null && params.paymentMethod !== KeckPaymentMethod.creditCard.value) {
|
|
148
|
+
throw new KasseneckValidationError('cancelReceipt', 'Kartendaten gibt es nur bei paymentMethod creditCard', 'request');
|
|
149
|
+
}
|
|
150
|
+
if (options.creditCardProvider != null) {
|
|
151
|
+
if (!Object.prototype.hasOwnProperty.call(CreditCardProvider, options.creditCardProvider)) {
|
|
152
|
+
throw new KasseneckValidationError('cancelReceipt', `Kartenanbieter: unbekannter Schluessel "${options.creditCardProvider}"`, 'request');
|
|
153
|
+
}
|
|
154
|
+
params.creditCardProvider = options.creditCardProvider;
|
|
155
|
+
}
|
|
156
|
+
if (options.cardPaymentId != null && options.cardPaymentId !== '')
|
|
157
|
+
params.cardPaymentId = options.cardPaymentId;
|
|
158
|
+
if (options.cardPaymentData != null)
|
|
159
|
+
params.cardPaymentData = options.cardPaymentData;
|
|
160
|
+
}
|
|
143
161
|
const daten = await rufen('cancelReceipt', params);
|
|
144
162
|
const receipt = belegAusHuelle(daten, 'cancelReceipt');
|
|
145
163
|
const huelle = daten;
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
* Nicht enthalten (bewusst): Rasterbilder/Logos, Capability-Profile einzelner
|
|
28
28
|
* Druckermodelle, Kassenlade, 1D-Barcodes.
|
|
29
29
|
*/
|
|
30
|
+
import { type QrModulGroesse } from './qr-groesse.js';
|
|
30
31
|
/** Papierbreite der Bonrolle. */
|
|
31
32
|
export type PosPaperSize = 'mm58' | 'mm80';
|
|
32
33
|
/** Ausrichtung einer Textzeile bzw. innerhalb einer Spalte. */
|
|
@@ -43,6 +44,14 @@ export type PosTextSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
|
|
43
44
|
export type QrSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
|
44
45
|
/** Fehlerkorrekturstufe des QR-Codes. */
|
|
45
46
|
export type QrCorrection = 'L' | 'M' | 'Q' | 'H';
|
|
47
|
+
/**
|
|
48
|
+
* Fertig gerechnetes QR-Raster, quadratisch, `true` = schwarzes Modul —
|
|
49
|
+
* **ohne** Ruhezone, die setzt der Drucker-Weg selbst.
|
|
50
|
+
*
|
|
51
|
+
* Dieses Paket rastert bewusst nicht selbst (keine Bildverarbeitung, siehe
|
|
52
|
+
* Kopf dieser Datei); wer den Bildweg braucht, bringt sein eigenes Raster mit.
|
|
53
|
+
*/
|
|
54
|
+
export type QrMatrix = readonly (readonly boolean[])[];
|
|
46
55
|
/** Textstil. Fehlende Felder gelten als Vorgabewert (nicht als "unveraendert"). */
|
|
47
56
|
export interface PosStyles {
|
|
48
57
|
bold?: boolean;
|
|
@@ -88,8 +97,26 @@ export interface EscPosHrOptions {
|
|
|
88
97
|
}
|
|
89
98
|
export interface EscPosQrOptions {
|
|
90
99
|
align?: PosAlign;
|
|
100
|
+
/**
|
|
101
|
+
* Feste Modulgroesse in Druckpunkten. Gesetzt schaltet sie die Rechnung ab —
|
|
102
|
+
* fuer Aufrufer, die genau wissen, was ihr Geraet kann. Ohne sie entscheidet
|
|
103
|
+
* die Regel in `qr-groesse.ts`.
|
|
104
|
+
*/
|
|
91
105
|
size?: QrSize;
|
|
92
106
|
correction?: QrCorrection;
|
|
107
|
+
/** Deckel fuer die gerechnete Modulgroesse; wirkungslos neben `size`. */
|
|
108
|
+
groesse?: QrModulGroesse;
|
|
109
|
+
/** Modell 1 des Symbols ausdruecklich waehlen — siehe `qrCodeBytes`. */
|
|
110
|
+
modell1?: boolean;
|
|
111
|
+
}
|
|
112
|
+
export interface EscPosQrRasterOptions {
|
|
113
|
+
align?: PosAlign;
|
|
114
|
+
/** Feste Punkte je Modul; ohne Angabe gerechnet (mindestens 1). */
|
|
115
|
+
punkteJeModul?: number;
|
|
116
|
+
/** Deckel fuer die gerechnete Groesse. */
|
|
117
|
+
groesse?: QrModulGroesse;
|
|
118
|
+
/** Ruhezone je Seite in Modulen; Vorgabe `QR_RUHEZONE_MODULE` (4). */
|
|
119
|
+
ruhezoneModule?: number;
|
|
93
120
|
}
|
|
94
121
|
/** Interner Stilzustand — immer vollstaendig, nie teilbefuellt. */
|
|
95
122
|
interface AktuelleStile {
|
|
@@ -111,6 +138,25 @@ interface AktuelleStile {
|
|
|
111
138
|
export interface EscPosDocument {
|
|
112
139
|
readonly paperSize: PosPaperSize;
|
|
113
140
|
readonly spaceBetweenRows: number;
|
|
141
|
+
/**
|
|
142
|
+
* Der Beleg ging ohne QR hinaus — `null`, solange alles in Ordnung ist.
|
|
143
|
+
* Gesetzt, wenn das Symbol auch mit der Ausnahmegroesse nicht auf das Papier
|
|
144
|
+
* passt und kein Bildweg mitgegeben wurde. Auf einer oesterreichischen Kassa
|
|
145
|
+
* ist der QR die maschinenlesbare Signatur: das muss der Aufrufer erfahren,
|
|
146
|
+
* ohne den Bytestrom zu durchsuchen.
|
|
147
|
+
*/
|
|
148
|
+
qrFehler: string | null;
|
|
149
|
+
/**
|
|
150
|
+
* Der QR steht auf dem Papier, aber nicht so wie eingestellt — `null`,
|
|
151
|
+
* solange nichts abgewichen ist. Zwei Faelle, beide mit Grund im Text: das
|
|
152
|
+
* Symbol war fuer den nativen Befehl zu breit und ging als Bild hinaus, oder
|
|
153
|
+
* es passte nur unter der Mindest-Modulgroesse.
|
|
154
|
+
*
|
|
155
|
+
* Getrennt von `qrFehler`, weil die Handlung eine andere ist: dort heisst es
|
|
156
|
+
* "Beleg ohne QR, nachdrucken oder elektronisch ausgeben", hier "gedruckt,
|
|
157
|
+
* aber der eingestellte Weg taugt fuer dieses Geraet nicht".
|
|
158
|
+
*/
|
|
159
|
+
qrAusweich: string | null;
|
|
114
160
|
/** intern: bisher erzeugte Bytes */
|
|
115
161
|
readonly bytes: number[];
|
|
116
162
|
/** intern: global gesetzte Codepage (ueberlebt `escPosReset`) */
|
|
@@ -213,7 +259,45 @@ export declare function escPosRow(doc: EscPosDocument, columns: readonly PosColu
|
|
|
213
259
|
export declare function qrCodeBytes(text: string, options?: {
|
|
214
260
|
size?: QrSize;
|
|
215
261
|
correction?: QrCorrection;
|
|
262
|
+
modell1?: boolean;
|
|
216
263
|
}): Uint8Array;
|
|
217
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* Setzt die Ausrichtung und haengt den nativen QR-Befehl an — mit
|
|
266
|
+
* **gerechneter** Modulgroesse, sofern `options.size` sie nicht festlegt.
|
|
267
|
+
*
|
|
268
|
+
* Ohne `size` entscheidet die Regel aus `qr-groesse.ts`: so gross wie
|
|
269
|
+
* moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` = der
|
|
270
|
+
* Bestandswert 4 dieses Pakets). Passt das Symbol auch mit der
|
|
271
|
+
* Ausnahmegroesse nicht aufs Papier, geht **kein** QR-Befehl hinaus und
|
|
272
|
+
* `doc.qrFehler` sagt warum: der Drucker schneidet ein zu breites Symbol
|
|
273
|
+
* nicht ab, er laesst es weg — ein Befehl, von dem man weiss, dass er nichts
|
|
274
|
+
* druckt, taeuschte nur einen Ausdruck vor. Den Bildweg kennt diese Ebene
|
|
275
|
+
* nicht; den faehrt `escPosQrRaster` bzw. der Belegweg in `layout-escpos.ts`.
|
|
276
|
+
*
|
|
277
|
+
* Eine leere Nutzlast geht unveraendert durch (fester Bestandsweg, keine
|
|
278
|
+
* Rechnung): sie ist ein Datenfehler, kein Papierfehler, und der Aufrufer
|
|
279
|
+
* behandelt sie ohnehin schon.
|
|
280
|
+
*/
|
|
218
281
|
export declare function escPosQrCode(doc: EscPosDocument, text: string, options?: EscPosQrOptions): void;
|
|
282
|
+
/**
|
|
283
|
+
* Der Bildweg: ein fertiges QR-Raster als Rasterbild (`GS v 0`) — der
|
|
284
|
+
* Notausgang, wenn der native Befehl das Symbol nicht auf das Papier bringt.
|
|
285
|
+
*
|
|
286
|
+
* Ein Pflichtbeleg ohne QR ist der schlechteste aller Ausgaenge; als Bild
|
|
287
|
+
* geht jedes Symbol hinaus, weil die Punkte je Modul hier bis auf 1 fallen
|
|
288
|
+
* duerfen. Dafuer ist das Bild langsamer und auf manchen Geraeten blasser.
|
|
289
|
+
*
|
|
290
|
+
* Das Raster selbst kommt vom Aufrufer (siehe `QrMatrix`): dieses Paket
|
|
291
|
+
* rechnet keine QR-Codes und verarbeitet keine Bilder.
|
|
292
|
+
*/
|
|
293
|
+
export declare function escPosQrRaster(doc: EscPosDocument, matrix: QrMatrix, options?: EscPosQrRasterOptions): void;
|
|
294
|
+
/**
|
|
295
|
+
* Punkte je Modul, mit denen `escPosQrRaster` ein Raster dieser Groesse auf
|
|
296
|
+
* dieses Papier bringt — dieselbe Rechnung, nur ohne Untergrenze 3: ein Bild
|
|
297
|
+
* darf bis auf einen Punkt je Modul schrumpfen und passt darum immer.
|
|
298
|
+
*/
|
|
299
|
+
export declare function qrRasterPunkte(paperSize: PosPaperSize, moduleAnzahl: number, options?: {
|
|
300
|
+
groesse?: QrModulGroesse;
|
|
301
|
+
ruhezoneModule?: number;
|
|
302
|
+
}): number;
|
|
219
303
|
export {};
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
* Nicht enthalten (bewusst): Rasterbilder/Logos, Capability-Profile einzelner
|
|
28
28
|
* Druckermodelle, Kassenlade, 1D-Barcodes.
|
|
29
29
|
*/
|
|
30
|
+
import { QR_DRUCK_PUNKTE, QR_MINDEST_PUNKTE, QR_MODUL_DECKEL, QR_RUHEZONE_MODULE, qrGroesseFuer, } from './qr-groesse.js';
|
|
30
31
|
// -------------------------------------------------------------- Befehlsbytes
|
|
31
32
|
// Wortwoertlich aus commands.dart. Die Zahlen sind ASCII-Codes der dortigen
|
|
32
33
|
// Zeichenketten: cCutFull = '$gs' + 'V0' ist GS 0x56 0x30 — die Ziffer '0',
|
|
@@ -61,6 +62,8 @@ const ZEILENUMBRUCH = 0x0a;
|
|
|
61
62
|
const CODEPAGE_ID = { CP437: 0, CP1252: 16 };
|
|
62
63
|
/** Korrekturstufen fuer GS ( k Funktion 169 — aus qrcode.dart. */
|
|
63
64
|
const QR_KORREKTUR = { L: 48, M: 49, Q: 50, H: 51 };
|
|
65
|
+
/** Nennbreite der Rolle in Millimetern — nur fuer Meldungstexte. */
|
|
66
|
+
const PAPIER_MM = { mm58: 58, mm80: 80 };
|
|
64
67
|
/** Druckbreite in Punkten je Papierformat — aus enums.dart (EscPaperSize.width). */
|
|
65
68
|
const PAPIER_BREITE = { mm58: 372, mm80: 558 };
|
|
66
69
|
/** Zeichen je Zeile nach Papier und Schrift — aus generator.dart. */
|
|
@@ -211,6 +214,8 @@ export function createEscPosDocument(options = {}) {
|
|
|
211
214
|
globalFont: null,
|
|
212
215
|
maxCharsPerLine: null,
|
|
213
216
|
styles: vollstaendigeStile(),
|
|
217
|
+
qrFehler: null,
|
|
218
|
+
qrAusweich: null,
|
|
214
219
|
};
|
|
215
220
|
}
|
|
216
221
|
/** Die bisher erzeugten Bytes als Kopie. */
|
|
@@ -225,6 +230,10 @@ export function escPosBytes(doc) {
|
|
|
225
230
|
export function escPosReset(doc) {
|
|
226
231
|
anhaengen(doc, C_INIT);
|
|
227
232
|
doc.styles = vollstaendigeStile();
|
|
233
|
+
// Wie `PrintPaper.reset()` im Flutter-Zwilling: ein neu begonnener Beleg
|
|
234
|
+
// erbt die QR-Meldungen des vorigen nicht.
|
|
235
|
+
doc.qrFehler = null;
|
|
236
|
+
doc.qrAusweich = null;
|
|
228
237
|
escPosSetGlobalCodeTable(doc, doc.globalCodeTable);
|
|
229
238
|
escPosSetGlobalFont(doc, doc.globalFont);
|
|
230
239
|
}
|
|
@@ -589,6 +598,16 @@ export function qrCodeBytes(text, options = {}) {
|
|
|
589
598
|
throw new Error('QR-Inhalt ist zu lang');
|
|
590
599
|
}
|
|
591
600
|
const bytes = [];
|
|
601
|
+
// Funktion 165: Symboltyp. Ohne diesen Befehl — dem Bestandsweg — waehlt der
|
|
602
|
+
// Drucker sein eigenes Modell, in aller Regel Modell 2. Genau das koennen
|
|
603
|
+
// manche guenstigen Geraete nicht: belegt ist eines, das unter dem Code eine
|
|
604
|
+
// "0" ausgibt, das Parameterbyte 0x30 des Druckbefehls, das es nicht als
|
|
605
|
+
// Befehl erkannt hat. Der Befehl geht deshalb nur hinaus, wenn er
|
|
606
|
+
// ausdruecklich verlangt ist; ein aufgedraengtes "Modell 2 fuer alle" waere
|
|
607
|
+
// eine stille Umstellung an jedem Bestandsgeraet.
|
|
608
|
+
if (options.modell1 === true) {
|
|
609
|
+
bytes.push(...C_QR_HEADER, 0x04, 0x00, 0x31, 0x41, 0x31, 0x00);
|
|
610
|
+
}
|
|
592
611
|
// Funktion 167: Modulgroesse
|
|
593
612
|
bytes.push(...C_QR_HEADER, 0x03, 0x00, 0x31, 0x43, size);
|
|
594
613
|
// Funktion 169: Fehlerkorrektur
|
|
@@ -604,15 +623,57 @@ export function qrCodeBytes(text, options = {}) {
|
|
|
604
623
|
bytes.push(...C_QR_HEADER, 0x03, 0x00, 0x31, 0x51, 0x30);
|
|
605
624
|
return Uint8Array.from(bytes);
|
|
606
625
|
}
|
|
607
|
-
/**
|
|
626
|
+
/**
|
|
627
|
+
* Setzt die Ausrichtung und haengt den nativen QR-Befehl an — mit
|
|
628
|
+
* **gerechneter** Modulgroesse, sofern `options.size` sie nicht festlegt.
|
|
629
|
+
*
|
|
630
|
+
* Ohne `size` entscheidet die Regel aus `qr-groesse.ts`: so gross wie
|
|
631
|
+
* moeglich, gedeckelt durch `options.groesse` (Vorgabe `auto` = der
|
|
632
|
+
* Bestandswert 4 dieses Pakets). Passt das Symbol auch mit der
|
|
633
|
+
* Ausnahmegroesse nicht aufs Papier, geht **kein** QR-Befehl hinaus und
|
|
634
|
+
* `doc.qrFehler` sagt warum: der Drucker schneidet ein zu breites Symbol
|
|
635
|
+
* nicht ab, er laesst es weg — ein Befehl, von dem man weiss, dass er nichts
|
|
636
|
+
* druckt, taeuschte nur einen Ausdruck vor. Den Bildweg kennt diese Ebene
|
|
637
|
+
* nicht; den faehrt `escPosQrRaster` bzw. der Belegweg in `layout-escpos.ts`.
|
|
638
|
+
*
|
|
639
|
+
* Eine leere Nutzlast geht unveraendert durch (fester Bestandsweg, keine
|
|
640
|
+
* Rechnung): sie ist ein Datenfehler, kein Papierfehler, und der Aufrufer
|
|
641
|
+
* behandelt sie ohnehin schon.
|
|
642
|
+
*/
|
|
608
643
|
export function escPosQrCode(doc, text, options = {}) {
|
|
609
644
|
escPosSetStyles(doc, { align: options.align ?? 'center' });
|
|
610
645
|
const qrOptionen = {};
|
|
611
|
-
if (options.size !== undefined)
|
|
612
|
-
qrOptionen.size = options.size;
|
|
613
646
|
if (options.correction !== undefined)
|
|
614
647
|
qrOptionen.correction = options.correction;
|
|
615
|
-
|
|
648
|
+
if (options.modell1 !== undefined)
|
|
649
|
+
qrOptionen.modell1 = options.modell1;
|
|
650
|
+
let drucken = true;
|
|
651
|
+
if (options.size !== undefined) {
|
|
652
|
+
qrOptionen.size = options.size;
|
|
653
|
+
}
|
|
654
|
+
else if (text !== '') {
|
|
655
|
+
const mass = qrGroesseFuer({
|
|
656
|
+
nutzlast: text,
|
|
657
|
+
papierbreitePunkte: QR_DRUCK_PUNKTE[doc.paperSize],
|
|
658
|
+
groesse: options.groesse ?? 'auto',
|
|
659
|
+
});
|
|
660
|
+
if (!mass.passt) {
|
|
661
|
+
doc.qrFehler =
|
|
662
|
+
`QR mit ${mass.module} Modulen ist fuer ${PAPIER_MM[doc.paperSize]} mm ` +
|
|
663
|
+
`(${QR_DRUCK_PUNKTE[doc.paperSize]} Punkte) zu breit`;
|
|
664
|
+
drucken = false;
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
if (mass.unterMindestmass) {
|
|
668
|
+
doc.qrAusweich =
|
|
669
|
+
`QR mit ${mass.module} Modulen passt nur mit ${String(mass.punkte)} Punkten ` +
|
|
670
|
+
`je Modul — unter dem Mindestmass von ${QR_MINDEST_PUNKTE}`;
|
|
671
|
+
}
|
|
672
|
+
qrOptionen.size = mass.punkte;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (drucken)
|
|
676
|
+
anhaengen(doc, qrCodeBytes(text, qrOptionen));
|
|
616
677
|
// Ausrichtung SOFORT zuruecksetzen: `ESC a` gilt nur am Zeilenanfang. Die
|
|
617
678
|
// Spalten-Positionierung (`ESC $`) schickt ihren Reset sonst mitten in der
|
|
618
679
|
// Zeile — Epson ignoriert ihn, und alles nach dem QR rueckte nach rechts
|
|
@@ -621,3 +682,76 @@ export function escPosQrCode(doc, text, options = {}) {
|
|
|
621
682
|
escPosSetStyles(doc, { align: 'left' });
|
|
622
683
|
}
|
|
623
684
|
}
|
|
685
|
+
/**
|
|
686
|
+
* Der Bildweg: ein fertiges QR-Raster als Rasterbild (`GS v 0`) — der
|
|
687
|
+
* Notausgang, wenn der native Befehl das Symbol nicht auf das Papier bringt.
|
|
688
|
+
*
|
|
689
|
+
* Ein Pflichtbeleg ohne QR ist der schlechteste aller Ausgaenge; als Bild
|
|
690
|
+
* geht jedes Symbol hinaus, weil die Punkte je Modul hier bis auf 1 fallen
|
|
691
|
+
* duerfen. Dafuer ist das Bild langsamer und auf manchen Geraeten blasser.
|
|
692
|
+
*
|
|
693
|
+
* Das Raster selbst kommt vom Aufrufer (siehe `QrMatrix`): dieses Paket
|
|
694
|
+
* rechnet keine QR-Codes und verarbeitet keine Bilder.
|
|
695
|
+
*/
|
|
696
|
+
export function escPosQrRaster(doc, matrix, options = {}) {
|
|
697
|
+
const module = matrix.length;
|
|
698
|
+
if (module <= 0)
|
|
699
|
+
throw new Error('QR-Raster ist leer');
|
|
700
|
+
for (const zeile of matrix) {
|
|
701
|
+
if (zeile.length !== module)
|
|
702
|
+
throw new Error('QR-Raster ist nicht quadratisch');
|
|
703
|
+
}
|
|
704
|
+
const ruhezone = options.ruhezoneModule ?? QR_RUHEZONE_MODULE;
|
|
705
|
+
if (!istGanzzahl(ruhezone) || ruhezone < 0) {
|
|
706
|
+
throw new Error('ruhezoneModule muss eine Ganzzahl >= 0 sein');
|
|
707
|
+
}
|
|
708
|
+
const gesamtModule = module + 2 * ruhezone;
|
|
709
|
+
let punkte = options.punkteJeModul;
|
|
710
|
+
if (punkte === undefined) {
|
|
711
|
+
const deckel = QR_MODUL_DECKEL[options.groesse ?? 'auto'];
|
|
712
|
+
punkte = Math.max(1, Math.min(deckel, Math.floor(QR_DRUCK_PUNKTE[doc.paperSize] / gesamtModule)));
|
|
713
|
+
}
|
|
714
|
+
if (!istGanzzahl(punkte) || punkte < 1) {
|
|
715
|
+
throw new Error('punkteJeModul muss eine Ganzzahl >= 1 sein');
|
|
716
|
+
}
|
|
717
|
+
const breite = gesamtModule * punkte;
|
|
718
|
+
const byteJeZeile = Math.ceil(breite / 8);
|
|
719
|
+
const daten = new Uint8Array(byteJeZeile * breite);
|
|
720
|
+
for (let y = 0; y < breite; y++) {
|
|
721
|
+
const modulY = Math.floor(y / punkte) - ruhezone;
|
|
722
|
+
if (modulY < 0 || modulY >= module)
|
|
723
|
+
continue;
|
|
724
|
+
const zeile = matrix[modulY];
|
|
725
|
+
for (let x = 0; x < breite; x++) {
|
|
726
|
+
const modulX = Math.floor(x / punkte) - ruhezone;
|
|
727
|
+
if (modulX < 0 || modulX >= module)
|
|
728
|
+
continue;
|
|
729
|
+
if (zeile[modulX] !== true)
|
|
730
|
+
continue;
|
|
731
|
+
const i = y * byteJeZeile + (x >> 3);
|
|
732
|
+
daten[i] = daten[i] | (0x80 >> (x & 7));
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
escPosSetStyles(doc, { align: options.align ?? 'center' });
|
|
736
|
+
// GS v 0 m xL xH yL yH d1...dk — m = 0: normale Dichte, 1:1.
|
|
737
|
+
anhaengen(doc, [
|
|
738
|
+
GS, 0x76, 0x30, 0x00,
|
|
739
|
+
byteJeZeile & 0xff, (byteJeZeile >> 8) & 0xff,
|
|
740
|
+
breite & 0xff, (breite >> 8) & 0xff,
|
|
741
|
+
...daten,
|
|
742
|
+
]);
|
|
743
|
+
anhaengen(doc, [ZEILENUMBRUCH]);
|
|
744
|
+
if ((options.align ?? 'center') !== 'left') {
|
|
745
|
+
escPosSetStyles(doc, { align: 'left' });
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Punkte je Modul, mit denen `escPosQrRaster` ein Raster dieser Groesse auf
|
|
750
|
+
* dieses Papier bringt — dieselbe Rechnung, nur ohne Untergrenze 3: ein Bild
|
|
751
|
+
* darf bis auf einen Punkt je Modul schrumpfen und passt darum immer.
|
|
752
|
+
*/
|
|
753
|
+
export function qrRasterPunkte(paperSize, moduleAnzahl, options = {}) {
|
|
754
|
+
const ruhezone = options.ruhezoneModule ?? QR_RUHEZONE_MODULE;
|
|
755
|
+
const deckel = QR_MODUL_DECKEL[options.groesse ?? 'auto'];
|
|
756
|
+
return Math.max(1, Math.min(deckel, Math.floor(QR_DRUCK_PUNKTE[paperSize] / (moduleAnzahl + 2 * ruhezone))));
|
|
757
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { type PosPaperSize, type PosAlign, type PosFont, type PosCutMode, type PosCodeTable, type PosTextSize, type QrSize, type QrCorrection, type PosStyles, type PosColumn, type EscPosOptions, type EscPosTextOptions, type EscPosHrOptions, type EscPosQrOptions, type EscPosDocument, createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
1
|
+
export { type PosPaperSize, type PosAlign, type PosFont, type PosCutMode, type PosCodeTable, type PosTextSize, type QrSize, type QrCorrection, type QrMatrix, type PosStyles, type PosColumn, type EscPosOptions, type EscPosTextOptions, type EscPosHrOptions, type EscPosQrOptions, type EscPosQrRasterOptions, type EscPosDocument, createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, escPosQrRaster, qrRasterPunkte, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
2
|
+
export { type QrModulGroesse, type QrGroesse, QR_MODUL_DECKEL, QR_RUHEZONE_MODULE, QR_MINDEST_PUNKTE, QR_AUSNAHME_PUNKTE, QR_HOECHST_PUNKTE, QR_DRUCK_PUNKTE, qrModulAnzahl, qrGroesseBerechnen, qrGroesseFuer, } from './qr-groesse.js';
|
|
2
3
|
export { escPosPrintableText } from './printable.js';
|
|
3
4
|
export { type UsbEndpointLike, type UsbAlternateLike, type UsbInterfaceLike, type UsbConfigurationLike, type UsbTransferOutResultLike, type UsbWriterLike, type UsbIdentityLike, type UsbDeviceLike, type UsbPrinterEndpoint, type UsbPrinterConnection, USB_VENDOR_EPSON, USB_CLASS_PRINTER, UsbTimeoutError, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
1
|
+
export { createEscPosDocument, escPosBytes, escPosReset, escPosSetGlobalCodeTable, escPosSetGlobalFont, escPosSetStyles, escPosText, escPosEmptyLines, escPosFeed, escPosCut, escPosHr, escPosRow, escPosQrCode, escPosQrRaster, qrRasterPunkte, encodeEscPosText, qrCodeBytes, escPosMaxCharsPerLine, escPosWortzeilen, wortzeilenText, } from './escpos.js';
|
|
2
|
+
export { QR_MODUL_DECKEL, QR_RUHEZONE_MODULE, QR_MINDEST_PUNKTE, QR_AUSNAHME_PUNKTE, QR_HOECHST_PUNKTE, QR_DRUCK_PUNKTE, qrModulAnzahl, qrGroesseBerechnen, qrGroesseFuer, } from './qr-groesse.js';
|
|
2
3
|
export { escPosPrintableText } from './printable.js';
|
|
3
4
|
export { USB_VENDOR_EPSON, USB_CLASS_PRINTER, UsbTimeoutError, usbDeviceKey, usbFindPrinterEndpoint, usbWriteAll, usbConnectPrinter, usbPrint, usbDisconnect, } from './webusb.js';
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { PosPaperSize, QrSize } from './escpos.js';
|
|
2
|
+
/**
|
|
3
|
+
* Die Rechenregel fuer die Modulgroesse des Beleg-QR — rein, ohne Drucker.
|
|
4
|
+
* Zwilling von `kasseneck_api/lib/src/printing/qr_groesse.dart` (Flutter).
|
|
5
|
+
*
|
|
6
|
+
* Vorgeschichte: der native QR-Befehl bekommt eine feste Modulgroesse in
|
|
7
|
+
* Druckpunkten mit und rechnet nicht nach, ob das Symbol aufs Papier passt.
|
|
8
|
+
* Ein Beleg-QR mit realer RKSV-Nutzlast hat 57 Module, mit Ruhezone also
|
|
9
|
+
* (57 + 8) Module breit; bei sechs Punkten je Modul sind das 390 Druckpunkte,
|
|
10
|
+
* und ein 58-mm-Kopf hat 384. Zu breit heisst bei den meisten Geraeten nicht
|
|
11
|
+
* "abgeschnitten", sondern **gar kein QR** — auf einem Pflichtbeleg der
|
|
12
|
+
* schlechteste aller Ausgaenge. (Im Flutter-Zwilling war genau das der
|
|
13
|
+
* belegte Fehler; dieses Paket druckt seit jeher mit vier Punkten und blieb
|
|
14
|
+
* darum verschont. Die Regel ist trotzdem dieselbe: sie deckelt auch eine
|
|
15
|
+
* ausdruecklich gewaehlte groessere Modulgroesse gegen den Papierrand ab.)
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Wie gross die Module des Beleg-QR werden duerfen — ein **Deckel**, keine
|
|
19
|
+
* Vorgabe: gedruckt wird immer die groesste Groesse, die noch aufs Papier
|
|
20
|
+
* passt, hoechstens aber diese hier.
|
|
21
|
+
*
|
|
22
|
+
* `auto` und `klein` decken beide bei 4 — das ist kein Versehen. 4 ist der
|
|
23
|
+
* Wert, den der native Weg dieses Pakets seit jeher druckt
|
|
24
|
+
* (`qrCodeBytes(..., size ?? 4)`); ohne diesen Deckel bekaeme jedes Geraet ab
|
|
25
|
+
* sofort ungefragt einen groesseren QR als gestern. `auto` heisst also
|
|
26
|
+
* "rechne, aber aendere den Bestand nicht".
|
|
27
|
+
*
|
|
28
|
+
* **Abweichung zum Flutter-Zwilling, bewusst:** dort deckelt `auto` bei 6,
|
|
29
|
+
* weil dort 6 der Bestandswert ist. Die Regel ist in beiden Paketen
|
|
30
|
+
* dieselbe — "so gross wie moeglich, hoechstens der Bestandswert" —, nur der
|
|
31
|
+
* Bestandswert unterscheidet sich. `mittel` (6) und `gross` (8) sind in
|
|
32
|
+
* beiden Paketen gleich; sie waehlt ein Mensch.
|
|
33
|
+
*/
|
|
34
|
+
export type QrModulGroesse = 'auto' | 'klein' | 'mittel' | 'gross';
|
|
35
|
+
/** Groesste Modulgroesse in Druckpunkten, die der jeweilige Deckel zulaesst. */
|
|
36
|
+
export declare const QR_MODUL_DECKEL: Readonly<Record<QrModulGroesse, number>>;
|
|
37
|
+
/**
|
|
38
|
+
* Ergebnis der Modulgroessen-Rechnung.
|
|
39
|
+
*
|
|
40
|
+
* Traegt bewusst mehr als die Zahl: ob ueberhaupt etwas passt (`passt`), ob
|
|
41
|
+
* nur unter der Mindestgroesse (`unterMindestmass`) und wie breit das Symbol
|
|
42
|
+
* wird (`breitePunkte`). Eine blosse Zahl haette die Ausnahme verschwiegen.
|
|
43
|
+
*/
|
|
44
|
+
export interface QrGroesse {
|
|
45
|
+
/**
|
|
46
|
+
* Modulgroesse in Druckpunkten, `null` wenn das Symbol auch mit der
|
|
47
|
+
* Ausnahmegroesse nicht aufs Papier passt.
|
|
48
|
+
*/
|
|
49
|
+
readonly punkte: QrSize | null;
|
|
50
|
+
/** Modulanzahl des Symbols (ohne Ruhezone). */
|
|
51
|
+
readonly module: number;
|
|
52
|
+
/** Gesamtbreite inklusive Ruhezone in Druckpunkten; 0, wenn nichts passt. */
|
|
53
|
+
readonly breitePunkte: number;
|
|
54
|
+
/**
|
|
55
|
+
* Gedruckt wird unter `QR_MINDEST_PUNKTE`. Erlaubt, aber eine Ausnahme, von
|
|
56
|
+
* der der Aufrufer erfahren muss — billige Thermodrucker und Handykameras
|
|
57
|
+
* tun sich damit schwer, besonders auf gewelltem Papier.
|
|
58
|
+
*/
|
|
59
|
+
readonly unterMindestmass: boolean;
|
|
60
|
+
/** Kurz fuer `punkte !== null`. */
|
|
61
|
+
readonly passt: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** Ruhezone je Seite, in Modulen (QR-Norm). */
|
|
64
|
+
export declare const QR_RUHEZONE_MODULE = 4;
|
|
65
|
+
/** Untergrenze: 4 Punkte sind bei 203 dpi rund 0,5 mm je Modul. */
|
|
66
|
+
export declare const QR_MINDEST_PUNKTE = 4;
|
|
67
|
+
/** Ausnahme, wenn `QR_MINDEST_PUNKTE` nicht passt — gemeldet, nicht still. */
|
|
68
|
+
export declare const QR_AUSNAHME_PUNKTE = 3;
|
|
69
|
+
/** Obergrenze des Druckbefehls in diesem Stack (`GS ( k` Funktion 167: 1..8). */
|
|
70
|
+
export declare const QR_HOECHST_PUNKTE = 8;
|
|
71
|
+
/**
|
|
72
|
+
* Druckbreite des Kopfes in Punkten (203 dpi): 58 mm = 384, 80 mm = 576 —
|
|
73
|
+
* Zwilling von `KeckPaperSize.druckPunkte`.
|
|
74
|
+
*
|
|
75
|
+
* Nicht dasselbe wie die Spaltenbreite in `escpos.ts` (372/558): die stammt
|
|
76
|
+
* aus `EscPaperSize.width` und laesst absichtlich Rand fuer die
|
|
77
|
+
* Textpositionierung. Wer rechnet, ob ein Symbol aufs Papier passt, braucht
|
|
78
|
+
* die echte Kopfbreite — ein QR, der auch nur einen Punkt zu breit ist, wird
|
|
79
|
+
* von den meisten Geraeten gar nicht gedruckt.
|
|
80
|
+
*/
|
|
81
|
+
export declare const QR_DRUCK_PUNKTE: Readonly<Record<PosPaperSize, number>>;
|
|
82
|
+
/**
|
|
83
|
+
* Modulanzahl, die `nutzlast` bei Fehlerkorrektur **M** braucht.
|
|
84
|
+
*
|
|
85
|
+
* Warum M, obwohl der native Befehl mit L druckt: M braucht bei gleicher
|
|
86
|
+
* Nutzlast gleich viele oder mehr Module als L. Wer mit M rechnet und mit L
|
|
87
|
+
* druckt, druckt nie breiter als gerechnet — die Rechnung ist konservativ,
|
|
88
|
+
* nie knapp. Umgekehrt waere sie eine Rechnung, die aufgeht, und ein Symbol,
|
|
89
|
+
* das ueber den Papierrand laeuft. Dasselbe gilt fuer die Byte-Zaehlung: hier
|
|
90
|
+
* zaehlt UTF-8 (wie im Flutter-Zwilling), waehrend `qrCodeBytes` die Nutzlast
|
|
91
|
+
* als Latin-1 sendet — UTF-8 ist nie kuerzer, die Rechnung also nie zu klein.
|
|
92
|
+
*
|
|
93
|
+
* Wirft, wenn die Nutzlast in keine Version passt — wie `qrCodeBytes` bei zu
|
|
94
|
+
* langem Inhalt. Ein still zurueckgegebenes "passt nicht" haette den
|
|
95
|
+
* Datenfehler als Papierfehler getarnt.
|
|
96
|
+
*/
|
|
97
|
+
export declare function qrModulAnzahl(nutzlast: string): number;
|
|
98
|
+
/**
|
|
99
|
+
* Groesste Modulgroesse, mit der `moduleAnzahl` Module **samt Ruhezone** in
|
|
100
|
+
* `papierbreitePunkte` passen, gedeckelt durch `groesse`.
|
|
101
|
+
*
|
|
102
|
+
* Wirft bei sinnlosen Eingaben: eine Papierbreite von 0 oder ein Symbol ohne
|
|
103
|
+
* Module ist ein Programmierfehler, und ein still zurueckgegebenes "passt
|
|
104
|
+
* nicht" haette ihn als Druckerproblem getarnt.
|
|
105
|
+
*/
|
|
106
|
+
export declare function qrGroesseBerechnen(options: {
|
|
107
|
+
papierbreitePunkte: number;
|
|
108
|
+
moduleAnzahl: number;
|
|
109
|
+
groesse?: QrModulGroesse;
|
|
110
|
+
}): QrGroesse;
|
|
111
|
+
/**
|
|
112
|
+
* Wie `qrGroesseBerechnen`, nur mit der Modulanzahl aus `nutzlast`.
|
|
113
|
+
*
|
|
114
|
+
* Eine leere Nutzlast ergibt kein Symbol — sie "passt nicht", statt zu
|
|
115
|
+
* werfen: der Aufrufer behandelt den Fall ohnehin schon (leerer QR am Beleg
|
|
116
|
+
* ist ein Datenfehler, kein Papierfehler).
|
|
117
|
+
*/
|
|
118
|
+
export declare function qrGroesseFuer(options: {
|
|
119
|
+
nutzlast: string;
|
|
120
|
+
papierbreitePunkte: number;
|
|
121
|
+
groesse?: QrModulGroesse;
|
|
122
|
+
}): QrGroesse;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Groesste Modulgroesse in Druckpunkten, die der jeweilige Deckel zulaesst. */
|
|
2
|
+
export const QR_MODUL_DECKEL = {
|
|
3
|
+
auto: 4,
|
|
4
|
+
klein: 4,
|
|
5
|
+
mittel: 6,
|
|
6
|
+
gross: 8,
|
|
7
|
+
};
|
|
8
|
+
// --------------------------------------------------------------- Konstanten
|
|
9
|
+
/** Ruhezone je Seite, in Modulen (QR-Norm). */
|
|
10
|
+
export const QR_RUHEZONE_MODULE = 4;
|
|
11
|
+
/** Untergrenze: 4 Punkte sind bei 203 dpi rund 0,5 mm je Modul. */
|
|
12
|
+
export const QR_MINDEST_PUNKTE = 4;
|
|
13
|
+
/** Ausnahme, wenn `QR_MINDEST_PUNKTE` nicht passt — gemeldet, nicht still. */
|
|
14
|
+
export const QR_AUSNAHME_PUNKTE = 3;
|
|
15
|
+
/** Obergrenze des Druckbefehls in diesem Stack (`GS ( k` Funktion 167: 1..8). */
|
|
16
|
+
export const QR_HOECHST_PUNKTE = 8;
|
|
17
|
+
/**
|
|
18
|
+
* Druckbreite des Kopfes in Punkten (203 dpi): 58 mm = 384, 80 mm = 576 —
|
|
19
|
+
* Zwilling von `KeckPaperSize.druckPunkte`.
|
|
20
|
+
*
|
|
21
|
+
* Nicht dasselbe wie die Spaltenbreite in `escpos.ts` (372/558): die stammt
|
|
22
|
+
* aus `EscPaperSize.width` und laesst absichtlich Rand fuer die
|
|
23
|
+
* Textpositionierung. Wer rechnet, ob ein Symbol aufs Papier passt, braucht
|
|
24
|
+
* die echte Kopfbreite — ein QR, der auch nur einen Punkt zu breit ist, wird
|
|
25
|
+
* von den meisten Geraeten gar nicht gedruckt.
|
|
26
|
+
*/
|
|
27
|
+
export const QR_DRUCK_PUNKTE = { mm58: 384, mm80: 576 };
|
|
28
|
+
/**
|
|
29
|
+
* Nutzlast in Byte, die eine QR-Version 1..40 bei Fehlerkorrektur **M** im
|
|
30
|
+
* Byte-Modus aufnimmt (ISO/IEC 18004, Tabelle 7).
|
|
31
|
+
*
|
|
32
|
+
* Byte-Modus, weil die RKSV-Nutzlast beliebige Zeichen traegt; Ziffern- oder
|
|
33
|
+
* Alphanumerik-Modus waere enger gefasst und wuerde fuer denselben Text
|
|
34
|
+
* weniger Module ergeben — also zu klein rechnen.
|
|
35
|
+
*/
|
|
36
|
+
const BYTE_KAPAZITAET_M = [
|
|
37
|
+
14, 26, 42, 62, 84, 106, 122, 152, 180, 213,
|
|
38
|
+
251, 287, 331, 362, 412, 450, 504, 560, 624, 666,
|
|
39
|
+
711, 779, 857, 911, 997, 1059, 1125, 1190, 1264, 1370,
|
|
40
|
+
1452, 1538, 1628, 1722, 1809, 1911, 1989, 2099, 2213, 2331,
|
|
41
|
+
];
|
|
42
|
+
// ------------------------------------------------------------- oeffentlich
|
|
43
|
+
/**
|
|
44
|
+
* Modulanzahl, die `nutzlast` bei Fehlerkorrektur **M** braucht.
|
|
45
|
+
*
|
|
46
|
+
* Warum M, obwohl der native Befehl mit L druckt: M braucht bei gleicher
|
|
47
|
+
* Nutzlast gleich viele oder mehr Module als L. Wer mit M rechnet und mit L
|
|
48
|
+
* druckt, druckt nie breiter als gerechnet — die Rechnung ist konservativ,
|
|
49
|
+
* nie knapp. Umgekehrt waere sie eine Rechnung, die aufgeht, und ein Symbol,
|
|
50
|
+
* das ueber den Papierrand laeuft. Dasselbe gilt fuer die Byte-Zaehlung: hier
|
|
51
|
+
* zaehlt UTF-8 (wie im Flutter-Zwilling), waehrend `qrCodeBytes` die Nutzlast
|
|
52
|
+
* als Latin-1 sendet — UTF-8 ist nie kuerzer, die Rechnung also nie zu klein.
|
|
53
|
+
*
|
|
54
|
+
* Wirft, wenn die Nutzlast in keine Version passt — wie `qrCodeBytes` bei zu
|
|
55
|
+
* langem Inhalt. Ein still zurueckgegebenes "passt nicht" haette den
|
|
56
|
+
* Datenfehler als Papierfehler getarnt.
|
|
57
|
+
*/
|
|
58
|
+
export function qrModulAnzahl(nutzlast) {
|
|
59
|
+
const laenge = new TextEncoder().encode(nutzlast).length;
|
|
60
|
+
for (let i = 0; i < BYTE_KAPAZITAET_M.length; i++) {
|
|
61
|
+
if (laenge <= BYTE_KAPAZITAET_M[i])
|
|
62
|
+
return 17 + 4 * (i + 1);
|
|
63
|
+
}
|
|
64
|
+
throw new Error('QR-Inhalt ist zu lang');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Groesste Modulgroesse, mit der `moduleAnzahl` Module **samt Ruhezone** in
|
|
68
|
+
* `papierbreitePunkte` passen, gedeckelt durch `groesse`.
|
|
69
|
+
*
|
|
70
|
+
* Wirft bei sinnlosen Eingaben: eine Papierbreite von 0 oder ein Symbol ohne
|
|
71
|
+
* Module ist ein Programmierfehler, und ein still zurueckgegebenes "passt
|
|
72
|
+
* nicht" haette ihn als Druckerproblem getarnt.
|
|
73
|
+
*/
|
|
74
|
+
export function qrGroesseBerechnen(options) {
|
|
75
|
+
const { papierbreitePunkte, moduleAnzahl } = options;
|
|
76
|
+
const groesse = options.groesse ?? 'auto';
|
|
77
|
+
if (!Number.isInteger(papierbreitePunkte) || papierbreitePunkte <= 0) {
|
|
78
|
+
throw new Error('papierbreitePunkte muss eine Ganzzahl > 0 sein');
|
|
79
|
+
}
|
|
80
|
+
if (!Number.isInteger(moduleAnzahl) || moduleAnzahl <= 0) {
|
|
81
|
+
throw new Error('moduleAnzahl muss eine Ganzzahl > 0 sein');
|
|
82
|
+
}
|
|
83
|
+
const roh = QR_MODUL_DECKEL[groesse];
|
|
84
|
+
if (roh === undefined) {
|
|
85
|
+
throw new Error(`Unbekannte QR-Modulgroesse: ${String(groesse)}`);
|
|
86
|
+
}
|
|
87
|
+
const gesamtModule = moduleAnzahl + QR_RUHEZONE_MODULE * 2;
|
|
88
|
+
const passend = Math.floor(papierbreitePunkte / gesamtModule);
|
|
89
|
+
if (passend < QR_AUSNAHME_PUNKTE) {
|
|
90
|
+
return { punkte: null, module: moduleAnzahl, breitePunkte: 0, unterMindestmass: false, passt: false };
|
|
91
|
+
}
|
|
92
|
+
const deckel = Math.min(Math.max(roh, QR_AUSNAHME_PUNKTE), QR_HOECHST_PUNKTE);
|
|
93
|
+
const punkte = passend < QR_MINDEST_PUNKTE ? QR_AUSNAHME_PUNKTE : Math.min(passend, deckel);
|
|
94
|
+
return {
|
|
95
|
+
punkte: punkte,
|
|
96
|
+
module: moduleAnzahl,
|
|
97
|
+
breitePunkte: gesamtModule * punkte,
|
|
98
|
+
unterMindestmass: punkte < QR_MINDEST_PUNKTE,
|
|
99
|
+
passt: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Wie `qrGroesseBerechnen`, nur mit der Modulanzahl aus `nutzlast`.
|
|
104
|
+
*
|
|
105
|
+
* Eine leere Nutzlast ergibt kein Symbol — sie "passt nicht", statt zu
|
|
106
|
+
* werfen: der Aufrufer behandelt den Fall ohnehin schon (leerer QR am Beleg
|
|
107
|
+
* ist ein Datenfehler, kein Papierfehler).
|
|
108
|
+
*/
|
|
109
|
+
export function qrGroesseFuer(options) {
|
|
110
|
+
if (options.nutzlast === '') {
|
|
111
|
+
return { punkte: null, module: 0, breitePunkte: 0, unterMindestmass: false, passt: false };
|
|
112
|
+
}
|
|
113
|
+
const weiter = {
|
|
114
|
+
papierbreitePunkte: options.papierbreitePunkte,
|
|
115
|
+
moduleAnzahl: qrModulAnzahl(options.nutzlast),
|
|
116
|
+
};
|
|
117
|
+
if (options.groesse !== undefined)
|
|
118
|
+
weiter.groesse = options.groesse;
|
|
119
|
+
return qrGroesseBerechnen(weiter);
|
|
120
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReceiptLayout } from './layout.js';
|
|
2
2
|
import type { PosPaperSize } from '../printing/escpos.js';
|
|
3
|
+
import { type QrModulGroesse } from '../printing/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* ePOS-Print XML (Epson TM-Drucker: Server Direct Print, ePOS-Print ueber
|
|
5
6
|
* HTTP) -- **aus dem Zeichenraster**: jede Rasterzeile wird eine <text>-Zeile
|
|
@@ -14,13 +15,49 @@ import type { PosPaperSize } from '../printing/escpos.js';
|
|
|
14
15
|
export interface EposPrintXmlOptions {
|
|
15
16
|
/** Zeichen je Zeile; Vorgabe nach `layout.paperSize` (32/48). */
|
|
16
17
|
zeichen?: number;
|
|
17
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* **Feste** QR-Modulgroesse (Epson `width` 3..16). Gesetzt schaltet sie die
|
|
20
|
+
* Rechnung ab -- dann passt der Aufrufer selbst auf, dass das Symbol samt
|
|
21
|
+
* Ruhezone auf die Rolle geht.
|
|
22
|
+
*/
|
|
18
23
|
qrBreite?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Deckel fuer die gerechnete QR-Modulgroesse; Vorgabe `mittel`.
|
|
26
|
+
*
|
|
27
|
+
* Warum `mittel` und nicht `auto`: `auto` deckelt beim Bestandswert des
|
|
28
|
+
* **ESC/POS**-Befehls dieses Pakets (4), dieser Weg druckt aber seit jeher
|
|
29
|
+
* mit 6. Die Vorgabe nennt den Bestandswert dieses Wegs also ausdruecklich,
|
|
30
|
+
* damit ohne Wahl kein Byte anders herauskommt.
|
|
31
|
+
*/
|
|
32
|
+
qrGroesse?: QrModulGroesse;
|
|
19
33
|
/** Papierschnitt am Ende, Vorgabe true. */
|
|
20
34
|
cut?: boolean;
|
|
21
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Das XML **samt** dem, was dem QR unterwegs zugestossen ist -- dieselbe
|
|
38
|
+
* Buchfuehrung wie `EscPosLayoutErgebnis` am ESC/POS-Weg.
|
|
39
|
+
*/
|
|
40
|
+
export interface EposPrintErgebnis {
|
|
41
|
+
xml: string;
|
|
42
|
+
/** Der Beleg ging ohne QR hinaus; das Symbol passt auch mit 3 Punkten nicht. */
|
|
43
|
+
qrFehler: string | null;
|
|
44
|
+
/** Der QR steht da, aber unter der Mindest-Modulgroesse. */
|
|
45
|
+
qrAusweich: string | null;
|
|
46
|
+
}
|
|
22
47
|
export declare function eposXmlEscape(text: string): string;
|
|
48
|
+
/** Nur das XML; wer die QR-Meldungen braucht, nimmt [eposPrintXmlErgebnis]. */
|
|
23
49
|
export declare function eposPrintXml(layout: ReceiptLayout, options?: EposPrintXmlOptions): string;
|
|
50
|
+
/**
|
|
51
|
+
* Wie [eposPrintXml], gibt aber zusaetzlich zurueck, was dem QR zugestossen
|
|
52
|
+
* ist.
|
|
53
|
+
*
|
|
54
|
+
* **Die QR-Modulgroesse wird gerechnet.** Vorher stand hier fest 6, unabhaengig
|
|
55
|
+
* von der Papierbreite: ein Beleg-QR mit realer RKSV-Nutzlast hat 57 Module,
|
|
56
|
+
* mit Ruhezone 65, bei sechs Punkten also 390 Druckpunkte -- und ein
|
|
57
|
+
* 58-mm-Kopf hat 384. Der Epson schneidet ein zu breites Symbol nicht ab, er
|
|
58
|
+
* laesst es weg; genau daran fehlte am echten Beleg der QR.
|
|
59
|
+
*/
|
|
60
|
+
export declare function eposPrintXmlErgebnis(layout: ReceiptLayout, options?: EposPrintXmlOptions): EposPrintErgebnis;
|
|
24
61
|
/**
|
|
25
62
|
* Epson-Drucker mit ePOS-Print direkt aus dem Browser ansprechen (ohne
|
|
26
63
|
* Server-Umweg): POST an `https://<ip>/cgi-bin/epos/service.cgi`. Der Drucker
|
|
@@ -36,6 +73,10 @@ export interface EposDirectOptions {
|
|
|
36
73
|
devid?: string;
|
|
37
74
|
/** Papier des Druckers -- bestimmt das Raster; Vorgabe: das des Layouts. */
|
|
38
75
|
papier?: PosPaperSize;
|
|
76
|
+
/** Feste QR-Modulgroesse; siehe [EposPrintXmlOptions.qrBreite]. */
|
|
77
|
+
qrBreite?: number;
|
|
78
|
+
/** Deckel fuer die gerechnete QR-Modulgroesse; siehe [EposPrintXmlOptions.qrGroesse]. */
|
|
79
|
+
qrGroesse?: QrModulGroesse;
|
|
39
80
|
timeoutMs?: number;
|
|
40
81
|
}
|
|
41
82
|
export interface EposResponse {
|