Initial: Projektstruktur, Referenz-Dokument, Implementierungsplan, Test-Skripte

This commit is contained in:
Hermes Agent
2026-07-02 15:29:19 +00:00
commit 5a7db008ee
5 changed files with 710 additions and 0 deletions
+198
View File
@@ -0,0 +1,198 @@
# Whiteboard Image Limits — Komplettdokumentation
> **Letztes Update:** 2026-07-02 · **Status:** 6 JS-Patches aktiv, OOM-Problem identifiziert, URL-Referenzen als Lösung geplant
---
## 1. Problem
Das Nextcloud Whiteboard (Excalidraw) hat mehrere hartkodierte Limits für Bildimporte:
| Limit | Default | Effekt |
|---|---|---|
| Downscale auf max. Kantenlänge | **1440px** (Excalidraw) + **1440px** (Whiteboard-eigener `image-blob-reduce`) | Bilder schrumpfen auf Briefmarken-Größe |
| Dateigrößen-Check | **4 MB** (Excalidraw) + **4 MB** (Whiteboard) | Größere Bilder werden abgelehnt |
| RAM-Verbrauch (Base64 im JSON) | **~50 MB/Bild** (4000×3000px decoded) | Ab ~3 Bildern → Chrome OOM-Crash |
Alle diese Limits sind **doppelt** vorhanden: einmal im Excalidraw-Core (`percentages-*.chunk.mjs`), einmal in der Whiteboard-Bridge (`NcSelect-*.chunk.mjs`).
---
## 2. Architektur: Warum kein Docker-Neustart nötig ist
```
Docker Image (read-only) Docker Volume (read-write)
┌──────────────────────────┐ ┌─────────────────────────────┐
│ Nextcloud PHP │ │ /custom_apps/whiteboard/js/ │
│ Apache/Nginx Config │ │ ├─ NcSelect-CknHatsl.mjs │ ← Patches #3#6
│ System-Libs │ │ ├─ percentages-*.mjs │ ← Patches #1#2
│ │ │ └─ whiteboard-*-patch.js │ ← Scroll + Quality
│ (NIE angefasst) │ │ │
└──────────────────────────┘ └─────────────────────────────┘
Persistiert über Restarts,
NICHT über App-Updates
```
**Der gesamte Bildverarbeitungs-Pipeline läuft im Browser:**
1. User dropped Bild → Whiteboard JS (`B0()` mit `image-blob-reduce`)
2. → Excalidraw JS (`initializeImage()`)
3. → Canvas-Rendering + Base64-Encode
4. → Upload JSON an Nextcloud (PHP macht **nichts** mit dem Bild)
Deshalb reicht ein **Browser-Cache-Refresh (Cachebuster)** — kein Container-Neustart.
---
## 3. Alle Patches (Stand 2026-07-02)
### 3.1 Scroll-Zoom (Miro-like)
**Datei:** `scripts/whiteboard-scroll-patch.js`
- Scrollen = Zoomen, Mittelklick-Drag = Pannen
- Registriert in `LoadViewerListener.php`, `WhiteboardDirectEditor.php`, `RecordingController.php`
### 3.2 Image Quality (Post-Processing)
**Datei:** `scripts/whiteboard-image-patch.js`
- Verhindert Qualitätsverlust durch Excalidraws internes `imageBlobReduce`-Postprocessing
### 3.3 `IM` und `TM` — Whiteboard-eigene Limits
**Datei:** `percentages-BXMCSKIN-D6x-nnv3.chunk.mjs`
```
...Cl=2,Ff=[1,2,3],dl=10,IM=1/0,TM=100*1024*1024,je=...
```
| Konstante | Vorher | Nachher | Bedeutung |
|---|---|---|---|
| `IM` | `1440` | `1/0` (=∞) | Max. Kantenlänge für `image-blob-reduce` |
| `TM` | `4*1024*1024` | `100*1024*1024` | Max. Dateigröße für Whiteboard-Preprocessing |
### 3.4 `maxImageSizeBytes` — Excalidraw-Fallback
**Datei:** `NcSelect-CknHatsl.chunk.mjs`
```
maxImageSizeBytes:F||9e15
```
| Vorher | Nachher |
|---|---|
| `F` (Nextcloud Config, `undefined` → 4MB Hardcoded) | `F\|\|9e15` (Fallback ≈ unendlich) |
### 3.5 `maxWidthOrHeight` + `imageOptions` — Excalidraw-Limits
**Datei:** `NcSelect-CknHatsl.chunk.mjs`
```
maxWidthOrHeight:8192,imageOptions:{maxWidthOrHeight:1/0,maxFileSizeBytes:1/0}
```
| Property | Vorher | Nachher |
|---|---|---|
| `maxWidthOrHeight` | `2048` (harter Reject) | `8192` |
| `imageOptions.maxWidthOrHeight` | `1440` (Downscale) | `1/0` (=∞) |
| `imageOptions.maxFileSizeBytes` | `4*1024*1024` (fileTooBig) | `1/0` (=∞) |
### 3.6 Infrastruktur
| Ebene | Einstellung | Wert |
|---|---|---|
| Nextcloud DB | `occ config whiteboard maxFileSize` | `100` (MB) |
| PHP | `upload_max_filesize` | `512M` |
| PHP | `post_max_size` | `512M` |
| PHP | `memory_limit` | `512M` |
| Nginx | `client_max_body_size` | `0` (unlimited) |
| Nginx | Whiteboard JS/CSS `Cache-Control` | `no-cache, no-store, must-revalidate` |
| Cache | `theming cachebuster` | **26** |
---
## 4. Warum das nicht reicht (OOM-Problem)
Mit `IM=1/0` und `imageOptions.maxWidthOrHeight=1/0` wird kein Downscaling mehr gemacht. Das bedeutet aber: **Jedes importierte Bild wird in voller原生auflösung als Base64 im Excalidraw-JSON gespeichert.**
**RAM-Verbrauch pro Bild:**
```
Breite × Höhe × 4 Bytes (RGBA decoded) + Base64-String (~33% Overhead)
5000 × 2000 × 4 = 40 MB decoded + 13 MB Base64 = ~53 MB RAM/Bild
4000 × 3000 × 4 = 48 MB decoded + 16 MB Base64 = ~64 MB RAM/Bild
```
**Bei 3 Bildern → ~160 MB + UI-Overhead → OOM-Crash nach ~2 Minuten.**
---
## 5. Excalidraw vs. Miro: Der fundamentale Unterschied
| | Excalidraw/Whiteboard | Miro |
|---|---|---|
| Bild-Speicherung | **Base64 inline im JSON** | URL-Referenz auf Server |
| Rendering | Canvas 2D, alle Bilder immer im RAM | WebGL + Tiled-Streaming |
| LOD | ❌ Nicht vorhanden | ✅ Nur sichtbare Kacheln geladen |
| RAM pro 4K-Bild | ~50 MB | ~0 MB (lazy, GPU-Textur) |
| 50× 4K-Bilder | 💥 unmöglich | ✅ problemlos |
Miro speichert nur **URLs** (100 Bytes statt 50 MB) und lädt Bilder erst beim Hinscrollen.
---
## 6. Geplanter Fix: URL-Referenzen statt Base64
### Ansatz
Statt das Bild als `data:image/png;base64,...` im JSON zu speichern, soll nur eine **URL** gespeichert werden. Der Browser lädt das Bild dann nur bei Bedarf.
```
// JETZT:
"files": { "abc123": { "dataURL": "data:image/png;base64,iVBORw0K...", ... } }
// ZIEL:
"files": { "abc123": { "url": "/remote.php/dav/files/.../image.png", ... } }
```
### Was geändert werden muss
| Komponente | Änderung | Aufwand |
|---|---|---|
| **Whiteboard Import** | Bild als Nextcloud-Datei speichern (WebDAV), nicht als Base64 | JS-Patch |
| **Excalidraw JSON-Format** | `dataURL``url` (relativer Pfad) | JS-Patch |
| **Excalidraw Rendering** | `Image()` vom Server laden statt aus Base64 | JS-Patch |
| **Nextcloud CORS** | `Access-Control-Allow-Origin` für Bild-URLs | Config |
| **File-ID Mapping** | `fileId` → Nextcloud-Dateipfad | JS-Patch |
### Risiken
- Alles JS-Patches auf dem Volume → gehen bei App-Update verloren
- Startup-Script zur Wiederherstellung nötig
- Langfristig: Upstream-PR an Excalidraw/Whiteboard
---
## 7. Direkter Link zum Excalidraw-Upstream
- **DEFAULT_IMAGE_OPTIONS** (Source of Truth): [`packages/common/src/constants.ts#L340-L342`](https://github.com/excalidraw/excalidraw/blob/master/packages/common/src/constants.ts)
- **LOD Feature Request** (seit 2022 offen): [Issue #5334](https://github.com/excalidraw/excalidraw/issues/5334)
- **Image Resolution Bug**: [Issue #5334](https://github.com/excalidraw/excalidraw/issues/5334)
---
## 8. Verifikation
Server-seitig verifizieren (nach jedem Patch):
```bash
# NcSelect
curl -s "https://nextcloud.niklashmotion.art/custom_apps/whiteboard/js/NcSelect-CknHatsl.chunk.mjs?v=26" \
| grep -oP 'maxImageSizeBytes[^,]+|imageOptions:\{[^}]+\}'
# Percentages
curl -s "https://nextcloud.niklashmotion.art/custom_apps/whiteboard/js/percentages-BXMCSKIN-D6x-nnv3.chunk.mjs?v=26" \
| grep -oP 'IM=[^,]+|TM=[^,]+'
```
Automatisiert: `scripts/verify-whiteboard-patches.sh` (im Skill-Verzeichnis).
---
## 9. Nächste Schritte
1. [x] Alle Limits beseitigt (6 JS-Patches + Infrastruktur)
2. [ ] **4096px-Cap setzen** (Quick-Fix gegen OOM) — 2 Minuten, 12+ Bilder stabil
3. [ ] **URL-Referenzen implementieren** (echte Lösung) — 12 Tage Entwicklungszeit
4. [ ] Startup-Script für Persistenz über App-Updates
5. [ ] Langfristig: Upstream-PR für konfigurierbare Limits + URL-Referenzen