如何修复 flutter 中相机照片的错误旋转?

How to fix wrong rotation of photo from camera in flutter?

我正在使用最新的相机插件版本拍照,并且我正在使用来自 flutter 示例的代码。我是这样挑选相机的:

final cameras = await availableCameras();
final firstCamera = cameras.first;

这是在初始化里面:

_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。 问题是照片有时会以错误的方向拍摄。 (我对此很确定,因为照片也在数据库中旋转。)例如,在 3 岁的小米 phone 上,它工作完美,但在某个新的三星 phone 上,照片总是旋转。

如何确保旋转始终正确? (即使在 ios 台设备上)

您可以使用包 https://pub.dev/packages/flutter_exif_rotation
支持 iOSAndroid
在某些设备中,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 '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;
  }

Source

这对我有用:

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));

聚会有点晚了。要求 Flutter 旋转图像或类似操作真的是个坏主意,因为移动应用程序不是为这些目的而设计的。唯一合理的用例是要求 Flutter 调整图像大小,因为您不想通过移动连接向服务器发送高分辨率图像。我的解决方案是将您的完整尺寸(如果您愿意并在后端调整大小)或调整大小的图像从 Flutter 发送到后端,您可以在后端进行自动定位。我使用跨平台的 MagickNET lib 来完成这项工作,它工作得很好。通过这样做,您的 Flutter 代码会更干净整洁。

我知道这已经晚了,但我只是想分享我是如何解决我的问题的,您可以在初始化后或每次拍照前调用此函数,代码如下:

await _camCtrl.lockCaptureOrientation(DeviceOrientation.portraitUp);

这解决了我的问题,有人说它不适用于 iOS,但我还没有测试过,所以你可以测试一下,看看它是否与 [=15= 兼容] 与否。

--- 非常简单的解决方案 ---

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,
);

如果要旋转图片,可以使用https://pub.dev/packages/image来操作图片:

import 'package:image/image.dart';

如果您使用包“camera”,则无法使用 bakeOrientation 旋转图像(删除镜像效果),因为没有 exif 数据。

这对我使用“image_picker”或“相机”很有效。

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);

您可以使用此包 flutter_image_compress 来解决相机图像方向问题。请注意,此方法比使用 image 包方法更快。

这样使用:

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 设置为 truekeepExif 设置为 false旋转0