【问题标题】:How to fix wrong rotation of photo from camera in flutter?如何修复相机中照片的错误旋转?
【发布时间】:2020-02-11 19:23:30
【问题描述】:

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

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。 问题是照片有时会以错误的方向拍摄。 (我确定这一点,因为照片也在数据库中旋转。)例如,在 3 年的小米手机上,它可以完美运行,但在某款新的三星手机上,照片总是在旋转。

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

【问题讨论】:

    标签: flutter dart android-camera


    【解决方案1】:

    这对我有用:

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

    【讨论】:

    • 简单有效
    • 这条评论对我帮助很大!谢谢!
    • 这拯救了一天!谢谢你
    • 这对我来说很好,因为我已经在使用图像插件了,谢谢!太糟糕了,已经很慢的图像捕捉变得越来越慢,为什么这么严重的错误在 2 年多后仍然存在于颤动中
    • 这是最简单的解决方案。
    【解决方案2】:

    这是我的跨平台解决方案,不使用插件。

    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

    【讨论】:

    • 使用此代码。添加 await 以使您的函数接受 Future: File file2 = await fixExifRotation(imageFile.path);
    • if (height == width) { print('height == width'); fixedImage = img.copyRotate(originalImage, 90); return await originalFile.writeAsBytes(img.encodeJpg(fixedImage));
    • @Dominik 我不认为 if 条件是详尽的。我打印出 exifData['Image Orientation'].printable 并为我返回 '90 CW'。我认为这也需要在 If 语句中考虑。作为参考,我正在 iPad Mini 2 上进行测试。
    • 这是一个可接受的解决方案@DominikRoszkowski,但理想情况下,应该纠正和写出 exif 方向元数据,而不是实际修改底层图像数据的旋转,这不一定是无损操作。跨度>
    • 嗨,Dominik,这个解决方案太棒了。但是,我想知道为什么不能使用相同的方法来旋转已选择的文件?例如我使用 ImagePicker 并用这种方法旋转,然后我尝试用类似的方法旋转我的新文件,但它不起作用.. 请检查你检查这个问题吗? stackoverflow.com/questions/64498774/…
    【解决方案3】:

    你可以使用包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"/>
    

    代码 sn-p

    image = await FlutterExifRotation.rotateImage(path: image.path);
    
    //Note : iOS not implemented
    image = await FlutterExifRotation.rotateAndSaveImage(path: image.path);
    

    【讨论】:

    • 感谢您的回答,但是如果我想覆盖原始图像,我该如何使用 rotateImage 功能?
    • image = 等待 FlutterExifRotation.rotateAndSaveImage(path: image.path);但 iOS 不支持。
    • ios有什么解决办法吗?对于我的具体情况,我只需要始终将图像设置为纵向。
    • 文件图片 = 等待 FlutterExifRotation.rotateImage(path: path);不工作。异步函数从不返回任何内容
    • 刚刚在有问题的设备上尝试过,它仍在旋转照片。
    【解决方案4】:

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

    await _camCtrl.lockCaptureOrientation(DeviceOrientation.portraitUp);
    

    这解决了我的问题,有人说它在iOS上不起作用,但我没有测试它,所以你可以测试一下它是否与iOS兼容。

    【讨论】:

    • 谢谢!这正是我想要的。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

      import 'package:image/image.dart';
      

      如果您使用“相机”包,则无法使用 bakeOrientation 旋转图像(去除镜像效果),因为没有 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);
      

      【讨论】:

        【解决方案7】:

        您可以使用此软件包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 设置为 falserotate 设置为 0

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

          • 这会将每个图像旋转 180 度..
          • 这就是例子。您可以使用 img.flipHorizo​​ntal 函数翻转到您需要的另一侧。
          猜你喜欢
          • 1970-01-01
          • 2018-04-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多