compressImage method

Future<File?> compressImage({
  1. required File imageFile,
  2. required String outputPathWithFilename,
  3. required int outputSizeInKB,
})

Implementation

Future<File?> compressImage({
  required File imageFile,
  required String outputPathWithFilename,
  required int outputSizeInKB, // Size in KB
}) async {
  try {
    var imageBytes = await imageFile.readAsBytes();
    img.Image? image = img.decodeImage(imageBytes);
    const int minQuality = 30;
    if (image == null) {
      return imageFile;
    }
    File(outputPathWithFilename).writeAsBytesSync(imageBytes);
    File savedFile = File(outputPathWithFilename);

    int currentSizeKB = imageBytes.lengthInBytes ~/ 1000;
    int quality = 90;
    double scale = 1.0;
    const int maxIterations = 10;

    for (int i = 0; i < maxIterations && currentSizeKB > outputSizeInKB; i++) {
      // If quality already low, start scaling down dimensions too
      if (quality <= 50 && scale > 0.5) {
        scale *= 0.8; // reduce resolution by 20%
        int newWidth = (image!.width * scale).toInt();
        int newHeight = (image.height * scale).toInt();
        image = img.copyResize(image, width: newWidth, height: newHeight);
      }

      List<int> compressed = img.encodeJpg(image!, quality: quality);
      await savedFile.writeAsBytes(compressed);

      currentSizeKB = savedFile.lengthSync() ~/ 1000;
      if (currentSizeKB > outputSizeInKB) {
        // Lower quality more aggressively when close to limit
        quality = (quality - 10).clamp(minQuality, 100);
      } else {
        break;
      }
    }

    return savedFile;
  } catch (e) {
    throw Exception(e);
  }
}