[mob][photos] Improved handling of high resolution image rendering (#6442)

## Description

Previously, images larger than 160MP were downscaled to 16MP to avoid
crashes caused by
[this](https://github.com/flutter/flutter/issues/110331) flutter issue.

This update lowers the threshold to 100MP and increases the downscaling
resolution to 50MP, for a better balance between performance and image
quality.

## Tests

- Tested with 150MP and 200MP images on a Samsung A54 (8GB RAM).
- Verified that rendering a 50MP downscaled image increases memory
usage, but remains within acceptable limits.
This commit is contained in:
Ashil
2025-07-02 13:56:41 +05:30
committed by GitHub

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data' show Uint8List;
import 'package:flutter/material.dart';
@@ -69,7 +70,7 @@ class _ZoomableImageState extends State<ZoomableImage> {
// This is to prevent the app from crashing when loading 200MP images
// https://github.com/flutter/flutter/issues/110331
bool get isTooLargeImage => _photo.width * _photo.height > 160000000;
bool get isTooLargeImage => _photo.width * _photo.height > 100000000; //100MP
@override
void initState() {
@@ -385,23 +386,18 @@ class _ZoomableImageState extends State<ZoomableImage> {
ImageProvider imageProvider;
if (isTooLargeImage) {
_logger.info(
"Handling very large image (${_photo.width}x${_photo.height}) to prevent crash",
"Handling very large image (${_photo.width}x${_photo.height}) by decreasing resolution to 50MP to prevent crash",
);
final aspectRatio = _photo.width / _photo.height;
int targetWidth, targetHeight;
if (aspectRatio > 1) {
targetWidth = 4096;
targetHeight = (targetWidth / aspectRatio).round();
} else {
targetHeight = 4096;
targetWidth = (targetHeight * aspectRatio).round();
}
const maxPixels = 50000000;
final targetHeight = sqrt(maxPixels / aspectRatio);
final targetWidth = aspectRatio * targetHeight;
imageProvider = Image.file(
file,
gaplessPlayback: true,
cacheWidth: targetWidth,
cacheHeight: targetHeight,
cacheWidth: targetWidth.round(),
cacheHeight: targetHeight.round(),
).image;
} else {
imageProvider = Image.file(
@@ -482,23 +478,17 @@ class _ZoomableImageState extends State<ZoomableImage> {
Uint8List? compressedFile;
if (isTooLargeImage) {
_logger.info(
"Compressing very large image (${_photo.width}x${_photo.height}) more aggressively",
"Compressing very large image (${_photo.width}x${_photo.height}) more aggressively down to 50MP",
);
final aspectRatio = _photo.width / _photo.height;
int targetWidth, targetHeight;
if (aspectRatio > 1) {
targetWidth = 4096;
targetHeight = (targetWidth / aspectRatio).round();
} else {
targetHeight = 4096;
targetWidth = (targetHeight * aspectRatio).round();
}
const maxPixels = 50000000;
final targetHeight = sqrt(maxPixels / aspectRatio);
final targetWidth = aspectRatio * targetHeight;
compressedFile = await FlutterImageCompress.compressWithFile(
file.path,
minWidth: targetWidth,
minHeight: targetHeight,
minWidth: targetWidth.round(),
minHeight: targetHeight.round(),
quality: 85,
);
} else {