- Büyük resimler ilk yüklemede max 2048px'e downsampling (RAM ~1.6MB) - Zoom 1.5x stretch'i geçince full-res'e swap (orijinal çözünürlük) - Resim geçişinde eski provider evict + ImageCache.evict() (RAM leak) - Tiled render kodu tamamen kaldırıldı
102 lines
2.8 KiB
Markdown
102 lines
2.8 KiB
Markdown
# Yönerge: Downsampling + Full-Res Swap + RAM Leak Fix
|
||
|
||
## Amaç
|
||
Yüksek çözünürlüklü görsellerde RAM tüketimini azaltmak ve resim geçişlerinde bellek sızıntısını gidermek.
|
||
|
||
## Dosya
|
||
`lib/widgets/image_canvas.dart`
|
||
|
||
## 1. State değişkenleri ekle
|
||
|
||
`_ImageCanvasState` sınıfına aşağıdaki değişkenleri ekle:
|
||
|
||
```dart
|
||
ui.Image? _uiImage;
|
||
ui.Image? _fullResImage;
|
||
bool _fullResLoading = false;
|
||
bool _usingFullRes = false;
|
||
static const int _downsampleTarget = 2048;
|
||
```
|
||
|
||
## 2. `_loadUiImage()` — Downsample decode
|
||
|
||
Mevcut `_loadUiImage()` metodunu aşağıdaki gibi değiştir:
|
||
|
||
- `ui.instantiateImageCodec()` çağrısına `targetWidth: _downsampleTarget, targetHeight: _downsampleTarget` parametrelerini ekle
|
||
- Decode edilen resmin boyutunu `_uiImage` ve `_tiledImageSize` olarak kaydet
|
||
- Eğer decode boyutu target'tan büyükse → `_loadFullResImage(bytes)` başlat (arka plan)
|
||
- Eğer decode boyutu target'tan küçükse → resim zaten küçük, `_usingFullRes = true` yap
|
||
|
||
## 3. `_loadFullResImage()` — Arka plan full-res yükleme
|
||
|
||
Yeni metot:
|
||
|
||
```dart
|
||
Future<void> _loadFullResImage(Uint8List bytes) async {
|
||
if (_fullResLoading) return;
|
||
_fullResLoading = true;
|
||
try {
|
||
final codec = await ui.instantiateImageCodec(bytes);
|
||
final frame = await codec.getNextFrame();
|
||
if (mounted && !_usingFullRes) {
|
||
setState(() => _fullResImage = frame.image);
|
||
} else {
|
||
frame.image.dispose();
|
||
}
|
||
} catch (e) { /* log */ }
|
||
finally { _fullResLoading = false; }
|
||
}
|
||
```
|
||
|
||
## 4. `_checkFullResSwap()` — Zoom threshold'unda swap
|
||
|
||
Yeni metot. `_handleScroll()` içinde `_sc` güncellendikten sonra çağrılır.
|
||
|
||
- Downsample resmin ne kadar stretch edildiğini hesapla (`stretchX`, `stretchY`)
|
||
- `maxStretch >= 1.5` ise:
|
||
- `_uiImage?.dispose()`
|
||
- `_uiImage = _fullResImage`
|
||
- `_fullResImage = null`
|
||
- `_tiledImageSize` güncelle
|
||
- `_usingFullRes = true`
|
||
|
||
## 5. `_handleScroll()` — Swap kontrolü ekle
|
||
|
||
`_sc = newSc;` satırından sonra `_checkFullResSwap()` çağrısı ekle.
|
||
|
||
## 6. RAM Leak Fix — `didUpdateWidget`
|
||
|
||
Resim değiştiğinde eski tüm referansları temizle:
|
||
|
||
```dart
|
||
_uiImage?.dispose();
|
||
_fullResImage?.dispose();
|
||
_cachedFileImage?.evict();
|
||
_cachedProvider?.evict();
|
||
_cachedFileImage = null;
|
||
_cachedProvider = null;
|
||
_cachedPath = null;
|
||
_cachedCacheWidth = null;
|
||
PaintingBinding.instance.imageCache.evict(FileImage(File(old.filePath)));
|
||
```
|
||
|
||
## 7. `_resetView()` — Tüm state sıfırla
|
||
|
||
`_fullResImage`, `_fullResLoading`, `_usingFullRes` sıfırlansın.
|
||
|
||
## 8. `dispose()` — Her iki resmi de dispose et
|
||
|
||
```dart
|
||
_uiImage?.dispose();
|
||
_fullResImage?.dispose();
|
||
```
|
||
|
||
## 9. Import
|
||
|
||
`dart:typed_data` import'u ekle (`Uint8List` için).
|
||
|
||
## Sonuç
|
||
- İlk yükleme: max 2048px downsample (RAM ~1.6MB)
|
||
- Zoom ile yakınlaşınca: full-res swap (~512MB+ büyük resimlerde)
|
||
- Resim geçişinde: eski tüm cache dispose + evict
|