Die grafische Darstellung ist mit Hilfe von SWT und Apache PDFBox umgesetzt. Grundsätzlich ist die PDF-Rendering Library austauschbar. Zwischendurch hatte ich JPod im Einsatz. Zur Darstellung wird ein bestimmter Maßstab (Zoomlevel) verwendet.
Die Auswahl des Bereichs ist erforderlich, um eine der folgenden Operationen durchzuführen:
- Einfärben des Bereichs (schwärzen)
- Aufkleben einer digitalen Haftnotiz
- Digital stempeln
Bei der Umsetzung entsteht schnell ein Durcheinander, wenn man mit verschiedenen Koordinatensystemen, Maßstäben usw. arbeitet. Fest kodierte Umrechnungsfaktoren erschweren das Verständnis und die Wartung.
Im Beispiel kommt hinzu, dass die Y-Achse innerhalb des PDF invers ist, d.h. 0 ist unten und nicht oben.
Relative Koordinaten
Um die verschiedenen Koordinatensysteme voneinander zu entkoppeln bin ich dazu übergegangen, alle Angaben (x,y,width,height) relativ in Promille zu verarbeiten:
x(relativ) = x(absolut) / Seitenbreite * 1000 y(relativ) = y(absolut) / Seitenhöhe * 1000 width(relativ) = width(absolut) / Seitenbreite * 1000 height(relativ) = height(absolut) / Seitenhöhe * 1000
Promille bringt gegenüber Prozent einen entscheidenden Vorteil: Für die berechneten Werte reichen in der Regel Ganzzahlen (Integer) aus.
Die relativen Promille-Koordinaten werden im Zielkoordinatensystem wieder in absolute Koordinaten umgerechnet.
Das bringt folgende Vorteile:
- Keine Kodierung von Umrechnungsfaktoren zwischen den Koordinatensystemen
- Entkoppelung der Koordinatensysteme
- In der Darstellung verwendete Maßstäbe (Zoom) sind nicht relevant, da die relativen Verhältnisse immer gleich bleiben.
- Zur Transformation in relative bzw. absolute Koordinaten kann ein einfaches API verwendet werden (dazu später mehr)
Transform API
Zur Übergabe von ganzzahligen Promille Koordinaten habe ich zunächst eine ganze einfache Klasse erstellt:
/** * Ganzzahlige Koordinaten * * @author Peter Pinnau (peter@pinnau.biz) * */ public class Position { public int x; public int y; public int width; public int height; }
Für die Transformation und Berechnung der absoluten Koordinaten in den einzelnen Koordinatensystemen ist bei Apache PDFBox eine höhere Genauigkeit erforderlich. Dafür habe ich die einfache Klasse FloatPosition erstellt. Diese wird aber nur innerhalb eines Koordinatensystems verwendet.
/** * Float Koordinaten * * @author Peter Pinnau (peter@pinnau.biz) * */ public class FloatPosition { public float x; public float y; public float width; public float height; }Zur Transformation von ganzzahligen Koordinaten (Position) in Fließkommakoordinaten (FloatPosition) und zur Berechnung von relativen, absoluten und inversen Koordinaten habe ich eine statische Klasse Transform erstellt:
1: /**
2: * Statische Klasse zum Druchführen von Koordinaten- und Größentransformationen
3: *
4: * @author Peter Pinnau (peter@pinnau.biz)
5: *
6: */
7: public class Transform {
8:
9: /**
10: * Erzeugt eine FloatPosition aus einer Position
11: * @param p
12: * @return
13: */
14: public static FloatPosition fromPosition(Position p) {
15: FloatPosition pos = new FloatPosition();
16:
17: pos.x = p.x;
18: pos.y = p.y;
19:
20: pos.height = p.height;
21: pos.width = p.width;
22:
23: return pos;
24: }
25:
26: /**
27: * Erzeugt eine FloatPosition aus x,y,width und height
28: *
29: * @param x
30: * @param y
31: * @param width
32: * @param height
33: * @return
34: */
35: public static FloatPosition create(float x, float y, float width, float height) {
36: FloatPosition pos = new FloatPosition();
37:
38: pos.x = x;
39: pos.y = y;
40: pos.width = width;
41: pos.height = height;
42:
43: return pos;
44: }
45:
46: /**
47: * Berechnet eine absolute FloatPosition aus Promillewerten und einem Bezugsbereich
48: *
49: * @param promille
50: * @param area
51: * @return
52: */
53: public static FloatPosition fromPromille(FloatPosition promille, FloatPosition area) {
54: FloatPosition p = new FloatPosition();
55:
56: float widthFactor = area.width / 1000;
57: float heightFactor = area.height / 1000;
58:
59: p.x = promille.x * widthFactor;
60: p.y = promille.y * heightFactor;
61:
62: p.width = promille.width * widthFactor;
63: p.height = promille.height * heightFactor;
64:
65: return p;
66: }
67:
68: /**
69: * Berechnet Promillewerte aus absoluten Werten und einem Bezugsbereich
70: *
71: * @param pos
72: * @param area
73: * @return
74: */
75: public static FloatPosition toPromille(FloatPosition pos, FloatPosition area) {
76: FloatPosition p = new FloatPosition();
77:
78: p.x = pos.x * 1000 / area.width;
79: p.y = pos.y * 1000 / area.height;
80:
81: p.width = pos.width * 1000 / area.width;
82: p.height = pos.height * 1000 / area.height;
83:
84: return p;
85: }
86:
87: /**
88: * Invertiert die Y-Achse
89: *
90: * y(neu) = area.height - y
91: *
92: * @param pos
93: * @param area
94: */
95: public static void invertY(FloatPosition pos, FloatPosition area) {
96: pos.y = area.height - pos.y;
97: }
98:
99: }
100:
Alle Methoden erhalten als Übergabeparameter eine Position-Instanz (ganzzahlige, relative Promille-Koordinaten).
Die absoluten Koordinaten im benötigten Koordinatensystem werden dann mit Hilfe der statischen Methoden aus Transform berechnet:
// Als Parameter übergebene relative Koordinaten Position position ... // Seite des PDF PDPage page = pdDocument.getPage(0); // CROPbox (kompletter Seitenbereich) PDRectangle pageSize = page.getCropBox(); // FloatPosition für komplette Seite erstellen (Bezugsbereich) FloatPosition area = Transform.create(0, 0, pageSize.width, pageSize.height); // Transform Promille Position to absolute FloatPosition FloatPosition transformed = Transform.fromPromille( Transform.fromPosition(position), area); // Y Achse invertieren (PDF Koordinaten) Transform.invertY(transformed, area); // => transformed enthält jetzt die absoluten Koordinaten im Zielsystem
Nachteil
Es müssen zunächst relative Koordinaten aus dem Quellsystem ermittelt werden und diese dann wieder in absolute Koordinaten des Zielsystems umgerechnet werden.
Insgesamt ergibt sich logischerweise wieder der feste Faktor, jedoch wird dieser nicht kodiert und ergibt sich immer automatisch anhand der verwendeten Koordinatensysteme.
Diesen geringen Performancenachteil kann ich in meinem System in Kauf nehmen, da keine Massenoperationen durchgeführt werden.
Die Lesbarkeit des Quelltextes hat sich erheblich verbessert und vor Allem sind die unterschiedlichen Koordinatensystem entkoppelt.
Keine Kommentare:
Kommentar veröffentlichen