# 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 _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