# Analiz: Aspect Ratio Bozulması + RAM Büyümesi Tarih: 2026-08-14 Sürüm: v1.3.0 sonrası regresyon --- ## 1. Aspect Ratio Bug'ı (kök neden bulundu) ### Belirti - Next/prev ile resim değişince görüntü **en/boy oranı bozulmuş** (gerilmiş/sıkışmış) geliyor. - Fazla zoom yapınca aspect düzeliyor. ### Kök Neden — `ResizeImagePolicy.exact` `lib/widgets/image_canvas.dart:429`: ```dart ResizeImage.resizeIfNeeded(effectiveWidth, effectiveWidth, _cachedFileImage!) ``` Bu çağrı Flutter SDK içinde şuna dönüşür (`image_provider.dart:1302-1310`): ```dart static ImageProvider resizeIfNeeded(int? cacheWidth, int? cacheHeight, provider) { if (cacheWidth != null || cacheHeight != null) { return ResizeImage(provider, width: cacheWidth, height: cacheHeight); } return provider; } ``` Ve `ResizeImage` constructor'ı (`image_provider.dart:1262-1268`): ```dart const ResizeImage(this.imageProvider, { this.width, this.height, this.policy = ResizeImagePolicy.exact, // ← VARSAYILAN exact this.allowUpscaling = false, }); ``` **`ResizeImagePolicy.exact`**: genişlik ve yüksekliği **bağımsız** ölçekler, aspect ratio'yu **koruMAZ**. Yani `width: 2048, height: 2048` demek → her resmi **2048×2048 kareye zorla**. 4000×2000 bir resim 2048×2048'e gerilir (2:1 → 1:1), görüntü bozulur. Zoom yapınca `_checkFullResSwap()` → `_usingFullRes = true` → `_cachedProvider = _cachedFileImage` (orijinal boyutlu `FileImage`, aspect doğru) → görüntü düzelir. Bu, belirtiyle birebir örtüşüyor. ### Düzeltme `resizeIfNeeded` yerine doğrudan `ResizeImage` + `policy: ResizeImagePolicy.fit`: ```dart _cachedProvider = effectiveWidth != null ? ResizeImage( _cachedFileImage!, width: effectiveWidth, height: effectiveWidth, policy: ResizeImagePolicy.fit, ) : _cachedFileImage; ``` `fit` policy'si (SDK `image_provider.dart:1378-1409`) aspect ratio'yu koruyarak 2048×2048 kutusuna **sığdırır**: - 4000×2000 → 2048×1024 (2:1 korunur) - 800×20000 dikey → 82×2048 (HATA-2'nin istediği dikey sınırlama da korunur) - 20000×800 panorama → 2048×82 > Not: `resizeIfNeeded` helper'ı `policy` parametresi **almaz**, bu yüzden `fit` > için `ResizeImage`'ı doğrudan kurmak zorunlu. --- ## 2. RAM Büyümesi Analizi ### Gözlem RAM 200MB'a kadar büyüdü. "Daha büyür mü?" — Evet, aşağıdaki modele göre büyüyebilir. ### RAM modeli (mevcut) | Kaynak | Boyut | |---|---| | Downsample (fit 2048×2048, RGBA) | en fazla 2048×2048×4 = **16.7MB** | | Full-res swap (zoom ≥ 1.5x) | resme bağlı: 12000px → **576MB**, 4000px → 64MB | | `ImageCache.maximumSize` | 16 entry | | `ImageCache.maximumSizeBytes` | 256MB | ### Neden 200MB'a büyüdü? 1. Kullanıcı zoom yaptı → `_checkFullResSwap` threshold 1.5 aşıldı → tam çözünürlük decode edildi → RAM'e ~100MB+ girdi. 2. Full-res resim **canlı** olduğu için `maximumSizeBytes = 256MB` sınırı onu **atamaz** (Flutter aktif kullanımdaki image'ı evict etmez). ### Daha büyür mü? — Evet, iki senaryo - **Daha büyük resim:** 12000px panorama full-res'e geçince tek resim ~576MB. `maximumSizeBytes = 256MB` canlı resmi korur, sınır aşılır. - **Çok sayıda full-res swap:** her resme zoom yapıp geçince, `didUpdateWidget` eski provider'ı `evict` eder ama evict **asenkron/gecikmeli** olabilir; ardışık hızlı geçişte 2-3 full-res aynı anda RAM'de kalabilir. ### Yapılacak iyileştirmeler 1. **Full-res swap'ı kademeli yap** (şu an binary: 2048 → full). Orta seviye (ör. 4096px) ekleyerek RAM'i sınırla. Ama bu kullanıcı isteği değilse yapma. 2. **`_checkFullResSwap` stretch eşiğini yükselt** (1.5 → 2.0) → daha az full-res swap, daha az RAM. Trade-off: zoom'da biraz daha geç keskinleşme. 3. **`maximumSizeBytes`'ı düşür** (256MB → 128MB) → LRU daha agresif. Ama canlı resmi yine korur, etkisi sınırlı. 4. **Full-res swap'ı dispose etme zamanlamasını netleştir** — şu an `didUpdateWidget` evict yapıyor; `dispose()` içine `_cachedProvider?.evict()` de eklenebilir. ### Karar önerisi Aspect bug'ı **kesin düzeltilmeli** (görsel regresyon, her resimde). RAM büyümesi ise full-res swap'ın **beklenen davranışı** — 200MB makul, ama 576MB'lık dev panoramalarda tek resimde patlayabilir. `fit` policy'ye geçmek downsample'ı da düzelteceği için ortalama RAM'i de bir miktar düşürür (exact kare yerine doğru orantılı küçük resim). --- ## 3. Öncelik Sırası 1. **Aspect bug fix** — `ResizeImagePolicy.fit` (tek satır, kritik görsel düzeltme) 2. **RAM** — şimdilik izle; 2. eşik/kademeli swap istersen ayrı yaparız. ## 4. Doğrulama - `flutter analyze`: 0 error - Release build: ✓ - Manuel test: kullanıcı (aspect düzelmesi + RAM gözlemi)