|
1 | | -# FastImage API Design - BufferedImage Kompatibilität |
| 1 | +# FastImage API Design — BufferedImage Compatibility & Modern High‑Performance API |
2 | 2 |
|
3 | | -## Ziel: "FastImage macht BufferedImage schneller" |
| 3 | +FastImage ist eine High‑Performance Image Processing Library für Java, die vollständig BufferedImage‑kompatibel ist und gleichzeitig eine moderne, fluente API bietet. |
4 | 4 |
|
5 | | -### Level 1: Drop-in Replacement (BufferedImage API) |
| 5 | +**Ziel:** „FastImage macht BufferedImage schneller" — ohne den bestehenden Java‑Code zu brechen. |
6 | 6 |
|
| 7 | +FastImage kombiniert: |
| 8 | +- Drop‑in Kompatibilität |
| 9 | +- Off‑Heap Speicher |
| 10 | +- SIMD‑Optimierungen (SSE/AVX) |
| 11 | +- Fluent API für moderne Workflows |
| 12 | +- Zero‑Copy Pipelines |
| 13 | + |
| 14 | +Damit wird FastImage zur praktischen, schnellen und sicheren Alternative zu BufferedImage. |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## 🎯 Ziel: „BufferedImage API + moderne Fluent API + native Geschwindigkeit" |
| 19 | + |
| 20 | +FastImage soll: |
| 21 | +- existierenden Java‑Code ohne Änderungen beschleunigen |
| 22 | +- neue Projekte mit einer modernen, chainable API unterstützen |
| 23 | +- Off‑Heap‑Speicher nutzen, um GC‑Pressure zu vermeiden |
| 24 | +- Bildoperationen 10–20× schneller ausführen als BufferedImage |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## 1. Level: Drop‑in Replacement (BufferedImage‑kompatibel) |
| 29 | + |
| 30 | +FastImage unterstützt die wichtigsten BufferedImage‑Methoden: |
| 31 | + |
| 32 | +- `getWidth()` |
| 33 | +- `getHeight()` |
| 34 | +- `getRGB(x, y)` |
| 35 | +- `setRGB(x, y, rgb)` |
| 36 | +- `getScaledInstance(width, height, hints)` |
| 37 | + |
| 38 | +### Beispiel: Migration ohne API‑Änderung |
| 39 | + |
| 40 | +**Vorher (BufferedImage):** |
7 | 41 | ```java |
8 | | -// Alt mit BufferedImage: |
9 | 42 | BufferedImage img = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB); |
| 43 | + |
10 | 44 | for (int y = 0; y < img.getHeight(); y++) { |
11 | 45 | for (int x = 0; x < img.getWidth(); x++) { |
12 | | - int rgb = img.getRGB(x, y); // LANGSAM! |
| 46 | + int rgb = img.getRGB(x, y); // LANGSAM |
13 | 47 | int gray = toGrayscale(rgb); |
14 | | - img.setRGB(x, y, gray); // LANGSAM! |
| 48 | + img.setRGB(x, y, gray); // LANGSAM |
15 | 49 | } |
16 | 50 | } |
| 51 | + |
17 | 52 | BufferedImage scaled = img.getScaledInstance(400, 300, Image.SCALE_SMOOTH); |
18 | 53 | ``` |
19 | 54 |
|
| 55 | +**Nachher (FastImage):** |
20 | 56 | ```java |
21 | | -// Neu mit FastImage (fast identisch, aber schnell): |
22 | 57 | FastImage img = FastImage.create(800, 600); |
| 58 | + |
23 | 59 | for (int y = 0; y < img.getHeight(); y++) { |
24 | 60 | for (int x = 0; x < img.getWidth(); x++) { |
25 | | - int rgb = img.getRGB(x, y); // SCHNELL! (direkter Speicherzugriff) |
| 61 | + int rgb = img.getRGB(x, y); // SCHNELL (direkter Off‑Heap Zugriff) |
26 | 62 | int gray = toGrayscale(rgb); |
27 | | - img.setRGB(x, y, gray); // SCHNELL! |
| 63 | + img.setRGB(x, y, gray); // SCHNELL |
28 | 64 | } |
29 | 65 | } |
| 66 | + |
30 | 67 | FastImage scaled = img.getScaledInstance(400, 300, FastImage.SCALE_BILINEAR); |
31 | 68 | ``` |
32 | 69 |
|
33 | | -**Unterschiede:** |
34 | | -- `TYPE_INT_ARGB` → implizit (immer ARGB) |
35 | | -- `Image.SCALE_*` → `FastImage.SCALE_BILINEAR`, `SCALE_BICUBIC`, `SCALE_NEAREST` |
| 70 | +### Unterschiede |
| 71 | + |
| 72 | +- `TYPE_INT_ARGB` → implizit, FastImage nutzt immer ARGB |
| 73 | +- `Image.SCALE_*` → ersetzt durch: |
| 74 | + - `SCALE_NEAREST` |
| 75 | + - `SCALE_BILINEAR` |
| 76 | + - `SCALE_BICUBIC` |
| 77 | + - `SCALE_LANCZOS` |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +## 2. Level: Moderne Fluent API (empfohlen für neue Projekte) |
36 | 82 |
|
37 | | -### Level 2: Moderne Fluent API (empfohlen für neue Projekte) |
| 83 | +Die Fluent API ist chainable, minimalistisch und performant. |
38 | 84 |
|
| 85 | +### Beispiel |
39 | 86 | ```java |
40 | | -// Fluent API für typische Workflows: |
41 | 87 | FastImage result = FastImage.fromFile("photo.jpg") |
42 | | - .resize(1920, 1080, FastImage.LANCZOS) |
43 | | - .adjust(brightness: 1.2f, contrast: 1.1f) |
44 | | - .blur(2.0f) |
45 | | - .sharpen(0.5f) |
46 | | - .toBufferedImage(); |
| 88 | + .resize(1920, 1080, FastImage.LANCZOS) |
| 89 | + .brightness(1.2f) |
| 90 | + .contrast(1.1f) |
| 91 | + .blur(2.0f) |
| 92 | + .toBufferedImage(); |
47 | 93 | ``` |
48 | 94 |
|
49 | | -### Vorgeschlagene komplette API: |
| 95 | +--- |
| 96 | + |
| 97 | +## 3. Vorgeschlagene vollständige API |
50 | 98 |
|
51 | 99 | ```java |
52 | 100 | public class FastImage { |
53 | | - |
| 101 | + |
54 | 102 | // === BufferedImage-kompatible Methoden === |
55 | | - |
56 | | - // Konstruktoren (ähnlich BufferedImage) |
| 103 | + |
57 | 104 | public static FastImage create(int width, int height); |
58 | | - public static FastImage create(int width, int height, int type); // type ignoriert, immer ARGB |
59 | | - |
60 | | - // Basis-Getter (identisch zu BufferedImage) |
| 105 | + public static FastImage create(int width, int height, int type); // type ignoriert |
| 106 | + |
61 | 107 | public int getWidth(); |
62 | 108 | public int getHeight(); |
63 | | - public int getRGB(int x, int y); // ⚡ Schnell (direkter Zugriff) |
64 | | - public void setRGB(int x, int y, int rgb); // ⚡ Schnell |
65 | | - |
66 | | - // Skalierung (ähnlich getScaledInstance, aber besser) |
| 109 | + public int getRGB(int x, int y); |
| 110 | + public void setRGB(int x, int y, int rgb); |
| 111 | + |
67 | 112 | public FastImage getScaledInstance(int width, int height, int hints); |
68 | | - |
69 | | - // === Moderne High-Performance Methoden === |
70 | | - |
| 113 | + |
| 114 | + // === Moderne High-Performance API === |
| 115 | + |
71 | 116 | // Geometrie |
72 | 117 | public FastImage resize(int width, int height); |
73 | | - public FastImage resize(int width, int height, int algorithm); // BILINEAR, BICUBIC, LANCZOS |
| 118 | + public FastImage resize(int width, int height, int algorithm); |
74 | 119 | public FastImage crop(int x, int y, int width, int height); |
75 | 120 | public FastImage flipHorizontal(); |
76 | 121 | public FastImage flipVertical(); |
77 | | - public FastImage rotate(double angle); // Bilinear interpolation |
78 | | - |
| 122 | + public FastImage rotate(double angle); |
| 123 | + |
79 | 124 | // Filter |
80 | | - public FastImage blur(float radius); // Gaussian blur |
81 | | - public FastImage sharpen(float amount); // Unsharp mask |
82 | | - public FastImage edgeDetect(); // Sobel operator |
| 125 | + public FastImage blur(float radius); |
| 126 | + public FastImage sharpen(float amount); |
| 127 | + public FastImage edgeDetect(); |
83 | 128 | public FastImage emboss(); |
84 | | - |
| 129 | + |
85 | 130 | // Farbe |
86 | 131 | public FastImage grayscale(); |
87 | 132 | public FastImage sepia(); |
88 | 133 | public FastImage invert(); |
89 | | - public FastImage brightness(float factor); // 0.0-2.0 |
90 | | - public FastImage contrast(float factor); // 0.0-2.0 |
91 | | - public FastImage saturation(float factor); // 0.0-2.0 |
92 | | - |
93 | | - // Convenience: Mehrere auf einmal |
94 | | - public FastImage adjust(Adjustment... adjustments); |
95 | | - |
| 134 | + public FastImage brightness(float factor); |
| 135 | + public FastImage contrast(float factor); |
| 136 | + public FastImage saturation(float factor); |
| 137 | + |
96 | 138 | // I/O |
97 | 139 | public static FastImage fromFile(String path); |
98 | 140 | public static FastImage fromBufferedImage(BufferedImage img); |
99 | 141 | public void saveToFile(String path, String format); |
100 | 142 | public BufferedImage toBufferedImage(); |
101 | | - |
102 | | - // Speicher-Management |
103 | | - public void dispose(); // Wichtig! Off-Heap-Speicher freigeben |
104 | | - |
105 | | - // Meta |
106 | | - public long getNativeMemoryUsage(); // Für Debugging |
107 | | - |
108 | | - // === Konstanten === |
109 | | - public static final int SCALE_NEAREST = 0; |
| 143 | + |
| 144 | + // Speicher |
| 145 | + public void dispose(); |
| 146 | + public long getNativeMemoryUsage(); |
| 147 | + |
| 148 | + // Konstanten |
| 149 | + public static final int SCALE_NEAREST = 0; |
110 | 150 | public static final int SCALE_BILINEAR = 1; |
111 | | - public static final int SCALE_BICUBIC = 2; |
112 | | - public static final int SCALE_LANCZOS = 3; |
| 151 | + public static final int SCALE_BICUBIC = 2; |
| 152 | + public static final int SCALE_LANCZOS = 3; |
113 | 153 | } |
114 | 154 | ``` |
115 | 155 |
|
116 | | -### Beispiel: Migration von BufferedImage |
| 156 | +--- |
| 157 | + |
| 158 | +## 4. Beispiel: Migration von BufferedImage |
117 | 159 |
|
| 160 | +**Vorher:** |
118 | 161 | ```java |
119 | | -// Vorher (BufferedImage): |
120 | 162 | public BufferedImage processImage(BufferedImage input) { |
121 | | - // Resize |
122 | 163 | BufferedImage scaled = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB); |
123 | 164 | Graphics2D g = scaled.createGraphics(); |
124 | 165 | g.drawImage(input, 0, 0, 800, 600, null); |
125 | 166 | g.dispose(); |
126 | | - |
127 | | - // Grayscale (langsam in Java) |
| 167 | + |
128 | 168 | for (int y = 0; y < scaled.getHeight(); y++) { |
129 | 169 | for (int x = 0; x < scaled.getWidth(); x++) { |
130 | 170 | int rgb = scaled.getRGB(x, y); |
131 | 171 | int gray = ...; |
132 | 172 | scaled.setRGB(x, y, gray); |
133 | 173 | } |
134 | 174 | } |
| 175 | + |
135 | 176 | return scaled; |
136 | 177 | } |
137 | 178 | ``` |
138 | 179 |
|
| 180 | +**Nachher:** |
139 | 181 | ```java |
140 | | -// Nachher (FastImage) - fast identisch: |
141 | 182 | public BufferedImage processImage(BufferedImage input) { |
142 | 183 | FastImage img = FastImage.fromBufferedImage(input) |
143 | | - .resize(800, 600) |
144 | | - .grayscale() |
145 | | - .brightness(1.1f); |
146 | | - |
| 184 | + .resize(800, 600) |
| 185 | + .grayscale() |
| 186 | + .brightness(1.1f); |
| 187 | + |
147 | 188 | BufferedImage result = img.toBufferedImage(); |
148 | | - img.dispose(); // WICHTIG! |
| 189 | + img.dispose(); |
149 | 190 | return result; |
150 | 191 | } |
151 | 192 | ``` |
152 | 193 |
|
153 | | -### Design-Entscheidungen: |
| 194 | +--- |
| 195 | + |
| 196 | +## 5. Design‑Entscheidungen |
154 | 197 |
|
155 | 198 | | Feature | Entscheidung | Grund | |
156 | 199 | |---------|--------------|-------| |
157 | | -| `getRGB`/`setRGB` | **Ja, aber schnell** | Drop-in compatibility | |
158 | | -| `TYPE_*` Konstanten | **Nein** | Immer ARGB, einfacher | |
159 | | -| `Graphics2D` | **Nein** | Nicht schnell machbar | |
160 | | -| `Raster`/`DataBuffer` | **Nein** | Direkter Speicherzugriff stattdessen | |
161 | | -| `ColorModel` | **Nein** | Immer sRGB | |
162 | | -| Fluent API | **Ja** | Moderne Java-Stil | |
163 | | -| `dispose()` | **Ja, wichtig!** | Off-Heap muss freigegeben werden | |
| 200 | +| `getRGB` / `setRGB` | Ja, aber schnell | Drop‑in Kompatibilität | |
| 201 | +| `TYPE_*` Konstanten | Nein | Immer ARGB, einfacher | |
| 202 | +| `Graphics2D` | Nein | Nicht performant | |
| 203 | +| `Raster` / `DataBuffer` | Nein | Direkter Off‑Heap Zugriff | |
| 204 | +| `ColorModel` | Nein | Immer sRGB | |
| 205 | +| Fluent API | Ja | Moderne Java‑Entwicklung | |
| 206 | +| `dispose()` | Ja, wichtig | Off‑Heap muss freigegeben werden | |
164 | 207 |
|
165 | | -### Empfehlung: |
| 208 | +--- |
166 | 209 |
|
167 | | -**FastImage = "BufferedImage API + moderne Fluent API + Geschwindigkeit"** |
| 210 | +## 6. Empfehlung |
168 | 211 |
|
169 | | -- Einfache Migration bestehenden Codes (BufferedImage-Methoden) |
170 | | -- Neue Features über Fluent API (resize().blur().grayscale()) |
171 | | -- Keine unerwarteten Performance-Fallen |
| 212 | +**FastImage = BufferedImage API + moderne Fluent API + native Geschwindigkeit** |
172 | 213 |
|
173 | | -Was denkst du? Soll ich die API in diese Richtung erweitern? |
| 214 | +- einfache Migration |
| 215 | +- moderne Workflows |
| 216 | +- keine Performance‑Fallen |
| 217 | +- ideal für FastGraphics, FastAI, FastVision |
0 commit comments