A6 quer: spaltenweise in ~10er-Bahnen statt pro Zeichen
Statt jede Glyphe einzeln umzusortieren (Rolle rückt pro Zeichen), wird jetzt in senkrechten Bahnen von ~10 Zeichen Breite gearbeitet: je Zeile ~10 Zeichen als Reihe, dann eine Zeile tiefer in derselben Bahn, erst danach die nächste Bahn. Rolle spult höchstens eine Bahnbreite zurück, 10er-Blöcke bleiben zusammen (natürlicher, schneller). Zeichenbreite wird aus dem SVG geschätzt; Bahnbreite über ?group=N einstellbar (Default 10). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1100,7 +1100,7 @@ const handler = (router, { services, getSchema, logger }) => {
|
|||||||
// behalten ihre Position. Das sichtbare Ergebnis ist identisch – nur die
|
// behalten ihre Position. Das sichtbare Ergebnis ist identisch – nur die
|
||||||
// Druckreihenfolge ändert sich, sodass der rollengeführte Plotter monoton in
|
// Druckreihenfolge ändert sich, sodass der rollengeführte Plotter monoton in
|
||||||
// Vorschubrichtung fährt statt je Zeile die Rolle zurückzuspulen (A6 quer).
|
// Vorschubrichtung fährt statt je Zeile die Rolle zurückzuspulen (A6 quer).
|
||||||
function svgSpaltenweise(svg) {
|
function svgSpaltenweise(svg, proReihe = 10) {
|
||||||
// <g>…</g>-Blöcke (z. B. eingebettete Signaturen) als Ganzes schützen – deren
|
// <g>…</g>-Blöcke (z. B. eingebettete Signaturen) als Ganzes schützen – deren
|
||||||
// innere Pfade dürfen NICHT umsortiert werden (sie hängen an einem eigenen
|
// innere Pfade dürfen NICHT umsortiert werden (sie hängen an einem eigenen
|
||||||
// Gruppen-Transform). Signaturen stehen hinter dem Text, daher greedy bis zum
|
// Gruppen-Transform). Signaturen stehen hinter dem Text, daher greedy bis zum
|
||||||
@@ -1110,17 +1110,31 @@ const handler = (router, { services, getSchema, logger }) => {
|
|||||||
const RE = /<path\b[^>]*\/>/g;
|
const RE = /<path\b[^>]*\/>/g;
|
||||||
const paths = safe.match(RE);
|
const paths = safe.match(RE);
|
||||||
if (!paths || paths.length < 2) return svg;
|
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*\)/);
|
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);
|
const d = p.match(/\bd\s*=\s*"\s*M\s*([-\d.]+)[\s,]+([-\d.]+)/i);
|
||||||
if (d) return [parseFloat(d[1]), parseFloat(d[2])];
|
if (d) return { x: parseFloat(d[1]), y: parseFloat(d[2]) };
|
||||||
return [0, 0];
|
return { x: 0, y: 0 };
|
||||||
};
|
};
|
||||||
const sorted = paths
|
const items = paths.map((p) => ({ p, ...pos(p) }));
|
||||||
.map((p) => ({ p, k: key(p) }))
|
// Zeichenbreite aus den x-Abstaenden aufeinanderfolgender Glyphen INNERHALB
|
||||||
.sort((a, b) => (a.k[0] - b.k[0]) || (a.k[1] - b.k[1]))
|
// einer Zeile schaetzen (x steigt in Leserichtung; Zeilenumbruch = x faellt).
|
||||||
.map((x) => x.p);
|
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 i = 0;
|
||||||
let out = safe.replace(RE, () => sorted[i++]);
|
let out = safe.replace(RE, () => sorted[i++]);
|
||||||
out = out.replace(/ | |||||||