How to fix wrong rotation of photo from camera in flutter?
Solution 1
You can use package https://pub.dev/packages/flutter_exif_rotation
Support iOS
and Android
In some devices the exif data shows picture in landscape mode when they're actually in portrait.
This plugin fixes the orientation for pictures taken with those devices.
For Android
Add this in your AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
code snippet
image = await FlutterExifRotation.rotateImage(path: image.path);
//Note : iOS not implemented
image = await FlutterExifRotation.rotateAndSaveImage(path: image.path);
Solution 2
This worked for me:
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));
Solution 3
This is my solution that works cross-platform and doesn't use plugins.
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;
}
Solution 4
I know this is late, but I just wanna to share how I fix my issue, you can call this function after it's initialized or every time before you take a photo, and here is the code:
await _camCtrl.lockCaptureOrientation(DeviceOrientation.portraitUp);
This fix my issue, somebody says it won't work on iOS, but I haven't test that it, so you can test it out and see if it is compatible with iOS or not.
Sprowk
Updated on June 07, 2022Comments
-
Sprowk almost 2 years
I'm taking a photo with the newest camera plugin version and I'm using code from flutter example. This is how I pick a camera:
final cameras = await availableCameras(); final firstCamera = cameras.first;
This is inside init:
_cameraController = CameraController( widget.camera, ResolutionPreset.medium, enableAudio: false, );
This is the rest of the relevant code:
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); } }
Afterwards, I show the photo to the user with
Image.file(File(_imagePath))
and later I send the photo to API. The problem is that the photo is sometimes captured with a wrong orientation. (I'm sure about this because the photo is also rotated in the database.) For example, on 3 years old Xiaomi phone, it works flawlessly, but on a certain new Samsung phone, the photo is always rotated.How to make sure that the rotation is always correct? (Even on ios devices)
-
Sprowk about 4 yearsThank you for your answer but how would I use the rotateImage function if I want to overwrite the original image?
-
chunhunghan about 4 yearsimage = await FlutterExifRotation.rotateAndSaveImage(path: image.path); but iOS not support.
-
Sprowk about 4 yearsIs there any solution for ios? For my specific case, I would only need to always set the image to portrait.
-
Sprowk about 4 yearsFile image = await FlutterExifRotation.rotateImage(path: path); Doesn't work. The async function never returns anything
-
chunhunghan about 4 yearscould you try example code Future getImageAndSave() async { File image = await ImagePicker.pickImage(source: ImageSource.gallery); if (image != null && image.path != null) { // Note : iOS not implemented image = await FlutterExifRotation.rotateAndSaveImage(path: image.path); if (image != null) { setState(() { _image = image; }); } } }
-
Sprowk about 4 yearsYour function above worked (instead of changing state inside the function I returned the image and then setState with image.path) File image = await getImageAndSave();
-
Sprowk about 4 yearsFuture fixExif(String path) async { File image = File(path); image = await FlutterExifRotation.rotateImage(path: image.path); return image; } This code ran on my phone. I'll test it on the problematic device today. Will it work on ios though?
-
chunhunghan about 4 yearsaccording to package's description. FlutterExifRotation.rotateImage also work on iOS.
-
Sprowk about 4 yearsJust tried it on the problematic device and it's still rotating the photo.
-
chunhunghan about 4 yearsI suggest post an issue to allow package owner check it.
-
Russo almost 4 yearsto use this code. add await to make your function accept Future<File>: File file2 = await fixExifRotation(imageFile.path);
-
Russo almost 4 yearsif (height == width) { print('height == width'); fixedImage = img.copyRotate(originalImage, 90); return await originalFile.writeAsBytes(img.encodeJpg(fixedImage));
-
Russo almost 4 yearsimage_picker: ^0.6.6+1 exif: ^1.0.2 image: ^2.1.12
-
teh_raab almost 4 years@Russo Did you get this working? I am using an iPad Mini 2, and when taking a photo in portrait if falls into the bottom else{} condition and does not rotation the image. If you have it working would you please be able to publish a working example
-
teh_raab almost 4 years@Dominik I dont think the if condition is exhaustive. I printed out the exifData['Image Orientation'].printable and it is returning '90 CW' for me. I think this also needs to be considered in the If statement. For reference, i am testing on an iPad Mini 2.
-
Dominik Roszkowski almost 4 yearsThanks @teh_raab for clarification!
-
Russo almost 4 years@teh_raab after taking the photo, it was rotated, but then after clicking on "confirm photo", then it becomes correctly oriented.
-
Maks over 3 yearsA post on the exiftool forum provides a full list of all the orientation values: 1 = Horizontal (normal) 2 = Mirror horizontal 3 = Rotate 180 4 = Mirror vertical 5 = Mirror horizontal and rotate 270 CW 6 = Rotate 90 CW 7 = Mirror horizontal and rotate 90 CW 8 = Rotate 270 CW
-
Maks over 3 yearsThis an acceptable solution @DominikRoszkowski but ideally just the exif orientation metadata should be corrected and written out instead of actually modifying the rotation of the underlying image data which will not be a necessarily a lossless operation.
-
Chris over 3 yearsHi Dominik, this solution is fantastic. However, I'm wondering why this same method can't be used to rotate a file that's already been selected? e.g. I use ImagePicker and rotate with this method, then I try to rotate my new file with a similar method but it doesn't work .. Please check you check this question? stackoverflow.com/questions/64498774/…
-
Ricardo Chen He over 3 yearssimple and effective
-
Felix over 3 yearsthis comment helped me so much! THANKS!
-
ChillBroDev over 3 yearsThis saved the day! Thanks for this
-
Nero over 3 yearsThis doesn't work for me and also the exif and image are both external plugins. Cannot say this solution doesn't use plugins. :)
-
HTMHell over 3 yearsThis solution worked for me, while
bakeOrientation
didn't. -
Andreas Toresäter about 3 yearsThis worked out good for me as I was already using the image plugin, thanks! Too bad the already slow capturing of an image gets even slower and worse why is such a severe bug still live in flutter after 2+ years
-
meteors about 3 yearsThis is the simplest solution which just worked.
-
Silverbaq almost 3 yearsThanks! This was exactly what I was looking for.
-
OnlyTarg over 2 yearsThanks a lot, sir!
-
leylekseven over 2 yearsyou saved me a lot! thank you, and alsı, we can do same operation process without file; like; final XFile image=await cameraController!.takePicture(); img.Image? capturedImage=img.decodeImage(await image.readAsBytes()); capturedImage=img.copyRotate(capturedImage!, 90); takenImage=Uint8List.fromList(img.encodePng(capturedImage));
-
Noldy Nayoan over 2 yearsUp until dec 2021, using the latest update of camera plugin, the orientation bug still exists (on Samsung A10 phone). This solution by Mark Laughton simply works!. Thanks.!
-
Aditya Patil over 2 yearsthis rotates every image by 180 degree..
-
Muhammad Tameem Rafay over 2 yearsthis is the example. you can use img.flipHorizantal function to flip to other side which you needed.
-
Mohammad Hosein about 2 yearsit is not for rotating its for flipping image. I had problem with front camera returning images flipped. This helped me a lot thanks