brendan-duncan / image

Dart Image Library for opening, manipulating, and saving various different image file formats.
MIT License
1.14k stars 255 forks source link

RangeError (index): Index out of range: index should be less than x: x #655

Open wim-veninga opened 1 month ago

wim-veninga commented 1 month ago

I'm selecting mutliple images via ImagePicker and passing them to a view model where I try to resize them. This is the code that does the resizing:

Future<File> resizeImageBasedOnFileSize(XFile file,
      {double targetSizeInBytes = 2 * 1024 * 1024}) async {
    File imageFile = File(file.path);
    int fileSize = await imageFile.length();
    //if (fileSize > targetSizeInBytes) {
    return await _createResizedImageFile(file, fileSize, targetSizeInBytes);
    //}
    //return imageFile;
  }

  Future<File> _createResizedImageFile(
      XFile file, int fileSize, double targetSizeInBytes) async {
    try {
      // Read the image bytes
      var bytes = await File(file.path).readAsBytes();

      Directory tempDir = await getTemporaryDirectory();
      String tempPath = '${tempDir.path}/raw_${file.name}.bin';
      File rawFile = File(tempPath);
      await rawFile.writeAsBytes(bytes);
      safePrint('Raw bytes data saved to: $tempPath');

      // Ensure the bytes are not empty
      if (bytes.isEmpty) {
        throw Exception("Image file is empty.");
      }

      // Find the appropriate decoder for the image data
      var decoder = img.findDecoderForData(bytes);
      if (decoder == null) {
        throw Exception("No suitable decoder found for the image data.");
      }

      // Decode the image
      var originalImage = decoder.decode(bytes);
      if (originalImage == null) {
        throw Exception("Failed to decode image.");
      }

      // Log the original image dimensions
      safePrint(
          "originalImage: ${originalImage.width}, ${originalImage.height}");

      // Calculate the scale factor and resize the image
      double scaleFactor = 1 / sqrt(fileSize / targetSizeInBytes);
      int newWidth = (originalImage.width * scaleFactor).round();
      img.Image resizedImage = img.copyResize(originalImage, width: newWidth);

      // Save the resized image to a file
      return await _saveResizedImageToFile(file, resizedImage);
    } catch (e) {
      safePrint("Error resizing image: $e");
      rethrow;
    }
  }

  Future<File> _saveResizedImageToFile(
      XFile file, img.Image resizedImage) async {
    Directory tempDir = await getTemporaryDirectory();
    String tempPath = '${tempDir.path}/resized_${file.name}.jpg';
    File resizedFile = File(tempPath);
    resizedFile.writeAsBytesSync(img.encodeJpg(resizedImage, quality: 100));
    return resizedFile;
  }

For certain images, the ones loaded on an andriod device via google photo's. The original photo's come from an ios device running ios 16. They are transfered to the andriod device via google photo's. The call to decoder.decode(bytes) fails for the image file attached (in binary format, I took the Raw bytes data saved to: $tempPath' of the failing image). The error is RangeError (index): Index out of range: index should be less than 1608715: 1608715 raw_eedac95e-2e30-4201-bebe-58b29d31bb88-1_all_255.jpg.bin.txt