Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image size compression takes too long and freezes the UI #19383

Closed
dshukertjr opened this issue Jul 15, 2018 · 16 comments
Closed

Image size compression takes too long and freezes the UI #19383

dshukertjr opened this issue Jul 15, 2018 · 16 comments
Labels
engine flutter/engine repository. See also e: labels. framework flutter/packages/flutter repository. See also f: labels. waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds

Comments

@dshukertjr
Copy link

I am trying to compress the size of the image before uploading it to firebase storage, but the image compression takes way too long and freezes the UI.

The code I am using is the following code, which was taken from
this stack overflow question:

import 'package:path_provider/path_provider.dart';
import 'dart:math' as Math;

void compressImage() async {
  File imageFile = await ImagePicker.pickImage();
  final tempDir = await getTemporaryDirectory();
  final path = tempDir.path;
  int rand = new Math.Random().nextInt(10000);

  Im.Image image = Im.decodeImage(imageFile.readAsBytesSync());
  Im.Image smallerImage = Im.copyResize(image, 500); // choose the size here, it will maintain aspect ratio

  var compressedImage = new File('$path/img_$rand.jpg')..writeAsBytesSync(Im.encodeJpg(image, quality: 85));
}````
@dshukertjr
Copy link
Author

It seems like this line is the one that is taking really long and freezing the UI.

Im.Image image = Im.decodeImage(imageFile.readAsBytesSync());

@adriancmurray
Copy link

Someone built an image compression component that uses native compression tools rather than what was provided with that image library. https://github.com/btastic/flutter_native_image

I recommend using that instead. The only real issue I've run into is an incompatibility with the Master Channel.

@zoechi
Copy link
Contributor

zoechi commented Jul 16, 2018

Alternatively you can use https://docs.flutter.io/flutter/foundation/compute.html to move computation off the UI thread to a new thread.
Some things like using plugins (platform channel) is not yet supported in such threads as far as I know.

@zoechi zoechi added framework flutter/packages/flutter repository. See also f: labels. engine flutter/engine repository. See also e: labels. labels Jul 16, 2018
@goderbauer
Copy link
Member

Where is Im.decodeImage defined? Are you using an external package to do the compression? In that case, the issue tracker for that package may be a better place to ask that question (or you use one of the suggestions from above to work around the slowness).

@goderbauer goderbauer added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Jan 2, 2019
@zoechi
Copy link
Contributor

zoechi commented Jan 28, 2019

Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now. Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away!
Thanks for your contribution.

@zoechi zoechi closed this as completed Jan 28, 2019
@moadqassem
Copy link

@goderbauer this line here Im.decodeImage represents the import 'package:image/image.dart' as Im;. Take a look at the stack overflow link.

@zoechi
Copy link
Contributor

zoechi commented Feb 24, 2019

Move the work to another isolate that you start up manually. This is not perfect yet.
compute() doesn't work for async results #25890 and the isolate needs to start up "manually".
Using isolates in this scenario currently also has the disadvantage that the image needs to be passed twice between the isolates.
There are discussions in dart-lang/language about allowing passing (immutable) data between isolates as reference to avoid copying
and #13937 is about allowing the use of plugins from isolates which would allow to upload from the additional isolate where the image was compressed directly.

@moadqassem
Copy link

@zoechi to be honest I have found another solution, not that great but works for my case at this point of time. What one can do, if the image_picker package is used I would simply use the maxHeight, maxWidth params. Again for the scenario that I have in had is ok. Thanks for the support mate.

@fvisticot
Copy link

image_picker work around is not the perfect solution. It would be fine to hav a elegant and performant solution to resize and compress image in pure dart language.
This performance issue needs to be re open

@zoechi
Copy link
Contributor

zoechi commented Feb 26, 2019

@fvisticot follow #26194

@vy12021
Copy link

vy12021 commented May 20, 2019

Start a platform thread as a plan b.

@aloisdeniel
Copy link

I can confirm that I successfuly resized an image from an isolate without locking the UI thread.

static Future<void> _resizeImage(String filePath) async {
    final file = File(filePath);

    final bytes = await file.readAsBytes();
    print("Picture original size: ${bytes.length}");

    final image = decodeImage(bytes);
    final resized = copyResize(image, 512);
    final resizedBytes = encodeJpg(resized, quality: 62);
    print("Picture resized size: ${resizedBytes.length}");

    await file.writeAsBytes(resizedBytes);
  }

// ...

await compute<String, void>(_resizeImage, filePath);
final resizedBytes = await File(filePath).readAsBytes();

The only drawback is that the image needs to be read again after execution.

@uKL
Copy link

uKL commented May 30, 2019

Unfortunately isolates approach doesn't seem to work for Flutter Web. The UI still freezes. Is it a known issue?

@optimygmbh
Copy link

The only drawback is that the image needs to be read again after execution.

@aloisdeniel Thanks for you idea. It works for me as well. But you don't need to save the file again.

You can try this:

static Future<List<int>> _resizeImage(File file) async {
    final bytes = await file.readAsBytes();
    final img.Image image = img.decodeImage(bytes);
    final img.Image resized = img.copyResize(image, width: 800);
    final List<int> resizedBytes = img.encodeJpg(resized, quality: 90);

    return resizedBytes;
  }

// ...

List<int> resizedBytes = await compute<File, List<int>>(_resizeImage, file);

@mdanics
Copy link

mdanics commented Jul 31, 2019

Looks like the image picker plugin now supports it 😃 #34523

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 29, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
engine flutter/engine repository. See also e: labels. framework flutter/packages/flutter repository. See also f: labels. waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds
Projects
None yet
Development

No branches or pull requests