diff --git a/extensions/directus-extension-skrift-orders/dist/index.js b/extensions/directus-extension-skrift-orders/dist/index.js index 36f4759..2f3b2b9 100644 --- a/extensions/directus-extension-skrift-orders/dist/index.js +++ b/extensions/directus-extension-skrift-orders/dist/index.js @@ -1100,7 +1100,7 @@ const handler = (router, { services, getSchema, logger }) => { // behalten ihre Position. Das sichtbare Ergebnis ist identisch – nur die // Druckreihenfolge ändert sich, sodass der rollengeführte Plotter monoton in // Vorschubrichtung fährt statt je Zeile die Rolle zurückzuspulen (A6 quer). - function svgSpaltenweise(svg) { + function svgSpaltenweise(svg, proReihe = 10) { // …-Blöcke (z. B. eingebettete Signaturen) als Ganzes schützen – deren // innere Pfade dürfen NICHT umsortiert werden (sie hängen an einem eigenen // Gruppen-Transform). Signaturen stehen hinter dem Text, daher greedy bis zum @@ -1110,17 +1110,31 @@ const handler = (router, { services, getSchema, logger }) => { const RE = /]*\/>/g; const paths = safe.match(RE); if (!paths || paths.length < 2) return svg; - const key = (p) => { + const pos = (p) => { const m = p.match(/matrix\(\s*[-\d.]+\s*,\s*[-\d.]+\s*,\s*[-\d.]+\s*,\s*[-\d.]+\s*,\s*([-\d.]+)\s*,\s*([-\d.]+)\s*\)/); - if (m) return [parseFloat(m[1]), parseFloat(m[2])]; + if (m) return { x: parseFloat(m[1]), y: parseFloat(m[2]) }; const d = p.match(/\bd\s*=\s*"\s*M\s*([-\d.]+)[\s,]+([-\d.]+)/i); - if (d) return [parseFloat(d[1]), parseFloat(d[2])]; - return [0, 0]; + if (d) return { x: parseFloat(d[1]), y: parseFloat(d[2]) }; + return { x: 0, y: 0 }; }; - const sorted = paths - .map((p) => ({ p, k: key(p) })) - .sort((a, b) => (a.k[0] - b.k[0]) || (a.k[1] - b.k[1])) - .map((x) => x.p); + const items = paths.map((p) => ({ p, ...pos(p) })); + // Zeichenbreite aus den x-Abstaenden aufeinanderfolgender Glyphen INNERHALB + // einer Zeile schaetzen (x steigt in Leserichtung; Zeilenumbruch = x faellt). + const gaps = []; + let prevX = null; + for (const it of items) { + if (prevX !== null && it.x - prevX > 0) gaps.push(it.x - prevX); + prevX = it.x; + } + gaps.sort((a, b) => a - b); + const zeichenBreite = gaps.length ? gaps[Math.floor(gaps.length / 2)] : 0; + if (!(zeichenBreite > 0)) return svg; // ohne Schaetzung nicht anfassen + const bahn = Math.max(1, proReihe) * zeichenBreite; + // Bahn (Spalte) primaer, darin Zeile (y) oben->unten, dann x links->rechts. + const sorted = items + .map((it, idx) => ({ it, idx, b: Math.floor(it.x / bahn) })) + .sort((a, b) => (a.b - b.b) || (a.it.y - b.it.y) || (a.it.x - b.it.x) || (a.idx - b.idx)) + .map((o) => o.it.p); let i = 0; let out = safe.replace(RE, () => sorted[i++]); out = out.replace(/G0/, () => bloecke[0]); @@ -1146,7 +1160,8 @@ const handler = (router, { services, getSchema, logger }) => { // Optional: SVG spaltenweise umsortieren (rollenschonend, A6 quer). if (ziel.endsWith('.svg') && String(req.query.reorder || '') === 'column') { try { - const umsortiert = svgSpaltenweise(fs.readFileSync(ziel, 'utf8')); + const proReihe = Math.max(1, Math.min(100, parseInt(req.query.group, 10) || 10)); + const umsortiert = svgSpaltenweise(fs.readFileSync(ziel, 'utf8'), proReihe); res.setHeader('Content-Type', 'image/svg+xml'); res.setHeader('Content-Disposition', `attachment; filename="${path.basename(ziel)}"`); return res.send(umsortiert); diff --git a/extensions/directus-extension-skrift-produktion/dist/index.js b/extensions/directus-extension-skrift-produktion/dist/index.js index b411adc..775546f 100644 --- a/extensions/directus-extension-skrift-produktion/dist/index.js +++ b/extensions/directus-extension-skrift-produktion/dist/index.js @@ -1486,7 +1486,7 @@ const Board = defineComponent({ h('input', { type: 'checkbox', checked: druck.spaltenweise, onChange: (e) => { druck.spaltenweise = e.target.checked; }, style: 'width:18px;height:18px;' }), h('span', { style: 'font-weight:600;' }, 'Rollenschonend drucken (spaltenweise)'), ]), - subdued('Für A6 quer: Zeichen werden spaltenweise (kurze Seite, oben→unten) gedruckt, damit die Rolle nicht je Zeile zurückfährt. Das sichtbare Ergebnis auf der Karte bleibt gleich – nur die Schriftstücke (nicht die Kuverts).', 'margin-top:6px;'), + subdued('Für A6 quer: es werden ~10 Zeichen je Reihe geschrieben, dann in derselben Bahn eine Zeile tiefer, erst danach die nächste Spalte. So spult die Rolle nur eine Bahnbreite zurück statt je Zeile die ganze Zeile. Sichtbares Ergebnis bleibt gleich – nur Schriftstücke, nicht Kuverts.', 'margin-top:6px;'), ]) : null, h('div', { style: 'margin:12px 0 4px;' }, [ segToggle(busy ? 'queue' : druck.mode, [