Как исправить неправильный поворот фото с камеры во флаттере?
Я делаю снимок с помощью новейшей версии плагина камеры и использую код из примера flutter. Вот как я выбираю камеру:
final cameras = await availableCameras();
final firstCamera = cameras.first;
Это внутри init:
_cameraController = CameraController(
widget.camera,
ResolutionPreset.medium,
enableAudio: false,
);
Это остальная часть соответствующего кода:
Future _takePhoto(BuildContext context) async {
try {
await _initializeControllerFuture;
final path = join(
(await getTemporaryDirectory()).path,
'${DateTime.now()}.png',
);
await _cameraController.takePicture(path);
setState(() {
_imagePath = path;
});
} catch (e) {
print(e);
}
}
После этого я показываю фото пользователю с Image.file(File(_imagePath))
а потом отправляю фото в API. Проблема в том, что фотография иногда получается с неправильной ориентацией. (Я уверен в этом, потому что фотография также повернута в базе данных.) Например, на телефоне Xiaomi 3-летнего возраста он работает безупречно, но на определенном новом телефоне Samsung фотография всегда поворачивается.
Как сделать так, чтобы вращение всегда было правильным? (Даже на устройствах с ios)
8 ответов
Вы можете использовать пакет https://pub.dev/packages/flutter_exif_rotation
SupportiOS
а также Android
На некоторых устройствах данные exif показывают изображение в альбомном режиме, когда они фактически находятся в портретном.
Этот плагин исправляет ориентацию изображений, сделанных на этих устройствах.
Для Android
Добавьте это в свойAndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
фрагмент кода
image = await FlutterExifRotation.rotateImage(path: image.path);
//Note : iOS not implemented
image = await FlutterExifRotation.rotateAndSaveImage(path: image.path);
Это сработало для меня:
import 'package:image/image.dart' as img;
...
final img.Image capturedImage = img.decodeImage(await File(path).readAsBytes());
final img.Image orientedImage = img.bakeOrientation(capturedImage);
await File(path).writeAsBytes(img.encodeJpg(orientedImage));
Это мое решение, которое работает на разных платформах и не использует плагины.
import 'dart:io';
import 'package:exif/exif.dart';
import 'package:image/image.dart' as img;
Future<File> fixExifRotation(String imagePath) async {
final originalFile = File(imagePath);
List<int> imageBytes = await originalFile.readAsBytes();
final originalImage = img.decodeImage(imageBytes);
final height = originalImage.height;
final width = originalImage.width;
// Let's check for the image size
// This will be true also for upside-down photos but it's ok for me
if (height >= width) {
// I'm interested in portrait photos so
// I'll just return here
return originalFile;
}
// We'll use the exif package to read exif data
// This is map of several exif properties
// Let's check 'Image Orientation'
final exifData = await readExifFromBytes(imageBytes);
img.Image fixedImage;
if (height < width) {
logger.logInfo('Rotating image necessary');
// rotate
if (exifData['Image Orientation'].printable.contains('Horizontal')) {
fixedImage = img.copyRotate(originalImage, 90);
} else if (exifData['Image Orientation'].printable.contains('180')) {
fixedImage = img.copyRotate(originalImage, -90);
} else if (exifData['Image Orientation'].printable.contains('CCW')) {
fixedImage = img.copyRotate(originalImage, 180);
} else {
fixedImage = img.copyRotate(originalImage, 0);
}
}
// Here you can select whether you'd like to save it as png
// or jpg with some compression
// I choose jpg with 100% quality
final fixedFile =
await originalFile.writeAsBytes(img.encodeJpg(fixedImage));
return fixedFile;
}
Вы можете использовать этот пакет flutter_image_compress для решения проблемы ориентации изображения камеры. Обратите внимание, что этот подход быстрее, чем использование пакета изображений .
Используйте это следующим образом:
import 'package:flutter_image_compress/flutter_image_compress.dart';
........
final fixedImageBytes = await FlutterImageCompress.compressWithFile(
image.path,
rotate: 0,
quality: 100,
keepExif: false,
autoCorrectionAngle: true,
format: CompressFormat.jpeg,
);
Примечание. Убедитесь, что для параметра autoCorrectionAngle установлено значение true , для параметра keepExif установлено значение false , а для поворота — значение 0 .
если вы хотите повернуть изображение, вы можете использовать https://pub.dev/packages/image для управления изображениями:
import 'package:image/image.dart';
Если вы используете пакет «камера», вы не можете повернуть изображение (удалить зеркальный эффект) с помощью BakOrientation, потому что у вас нет данных exif.
у меня это работает с использованием «image_picker» или «camera».
File originalFile = File.fromUri(Uri(path: file.path));
List<int> imageBytes = await originalFile.readAsBytes();
final Image originalImage = decodeImage(imageBytes)!;
final Image orientedImage = flipHorizontal(originalImage);
List<int> imageBytesOrientated = encodeJpg(orientedImage);
Для записи по тому же пути:
await File(path).writeAsBytes(imageBytesOrientated);
Я знаю, что это поздно, но я просто хочу поделиться тем, как я исправляю свою проблему, вы можете вызывать эту функцию после ее инициализации или каждый раз перед тем, как делать снимок, и вот код:
await _camCtrl.lockCaptureOrientation(DeviceOrientation.portraitUp);
Это исправляет мою проблему, кто-то говорит, что он не будет работать на iOS, но я не тестировал это, поэтому вы можете протестировать его и посмотреть, совместим ли он с iOS или нет.
Немного поздно на вечеринку. Это действительно плохая идея - просить Flutter вращать изображения или выполнять аналогичные операции, потому что мобильные приложения не предназначены для этих целей. Единственный разумный вариант использования - попросить Flutter изменить размер изображения, потому что вы не хотите отправлять изображение с высоким разрешением на свой сервер через мобильное соединение. Мое решение - отправить ваш полный размер (если вы предпочитаете и изменить размер в бэкэнде) или изображения с измененным размером из Flutter в бэкэнд, где вы можете выполнить автоматическую ориентацию. Я использую MagickNET lib, которая является кроссплатформенной для выполнения этой работы, и она отлично работает. Благодаря этому ваш код Flutter станет намного чище и аккуратнее.
--- ОЧЕНЬ ПРОСТОЕ РЕШЕНИЕ ---
import 'package:image/image.dart' as img;
XFile xfile = await _cameraController.takePicture();
List<int> imageBytes = await xfile.readAsBytes();
img.Image? originalImage = img.decodeImage(imageBytes);
img.Image fixedImage = img.flipVertical(originalImage!);
File file = File(xfile.path);
File fixedFile = await file.writeAsBytes(
img.encodeJpg(fixedImage),
flush: true,
);