[mob] perf: Decode images from which face is to be cropped, in an isolate to avoid jank
This commit is contained in:
parent
b022ef6d1e
commit
2f7e0cd1ef
1 changed files with 33 additions and 3 deletions
|
@ -1,7 +1,10 @@
|
|||
import "dart:io" show File;
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import "package:computer/computer.dart";
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:flutter/widgets.dart";
|
||||
import "package:flutter_image_compress/flutter_image_compress.dart";
|
||||
import "package:image/image.dart" as img;
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/face/model/face.dart";
|
||||
|
@ -40,6 +43,7 @@ class CroppedFaceImageView extends StatefulWidget {
|
|||
|
||||
class CroppedFaceImageViewState extends State<CroppedFaceImageView> {
|
||||
ui.Image? _image;
|
||||
final _computer = Computer.shared();
|
||||
final _logger = Logger("CroppedFaceImageView");
|
||||
|
||||
@override
|
||||
|
@ -79,17 +83,32 @@ class CroppedFaceImageViewState extends State<CroppedFaceImageView> {
|
|||
Future<ui.Image?> getImage() async {
|
||||
try {
|
||||
final faceBox = widget.face.detection.box;
|
||||
|
||||
final File? ioFile = await getFile(widget.enteFile);
|
||||
if (ioFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final image = await img.decodeImageFile(ioFile.path);
|
||||
img.Image? image = await _computer
|
||||
.compute(decodeImage, param: {"filePath": ioFile.path});
|
||||
|
||||
if (image == null) {
|
||||
throw Exception("Failed decoding image file ${widget.enteFile.title}}");
|
||||
_logger.info(
|
||||
"Failed to decode image ${widget.enteFile.title}. Compressing to jpg and decoding",
|
||||
);
|
||||
final compressedJPGImage =
|
||||
await FlutterImageCompress.compressWithFile(ioFile.path);
|
||||
image = await _computer.compute(
|
||||
decodeJPGImage,
|
||||
param: {"image": compressedJPGImage},
|
||||
);
|
||||
|
||||
if (image == null) {
|
||||
throw Exception("Failed to decode image");
|
||||
}
|
||||
}
|
||||
|
||||
final stopwatch = Stopwatch()..start();
|
||||
final croppedImage = img.copyCrop(
|
||||
image,
|
||||
x: (image.width * faceBox.xMin).round(),
|
||||
|
@ -98,7 +117,10 @@ class CroppedFaceImageViewState extends State<CroppedFaceImageView> {
|
|||
height: (image.height * faceBox.height).round(),
|
||||
antialias: false,
|
||||
);
|
||||
|
||||
_logger.info(
|
||||
"Image crop took ${stopwatch.elapsedMilliseconds}ms ----------------",
|
||||
);
|
||||
stopwatch.stop();
|
||||
return convertImageToFlutterUi(croppedImage);
|
||||
} catch (e, s) {
|
||||
_logger.severe("Error getting image", e, s);
|
||||
|
@ -106,3 +128,11 @@ class CroppedFaceImageViewState extends State<CroppedFaceImageView> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<img.Image?> decodeImage(Map args) async {
|
||||
return await img.decodeImageFile(args["filePath"]);
|
||||
}
|
||||
|
||||
img.Image? decodeJPGImage(Map args) {
|
||||
return img.decodeJpg(args["image"])!;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue