Как исправить неправильный поворот фото с камеры во флаттере?

Я делаю снимок с помощью новейшей версии плагина камеры и использую код из примера 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,
);
Другие вопросы по тегам