我正在开发 Xamarin.Forms 应用程序,我想在其中实现拍照功能。
我已经实现了这个功能及其工作原理。但刚才我在三星设备上遇到了一个问题。因此,当我从设备拍照时,它会自动旋转。但同样的行为在 Moto X 等其他设备上也能完美运行。
为了解决这个问题,我正在检查该图像的 ExifInterface,但不知何故它始终为 0。
对于拍照,我的代码片段如下:
var image = await CrossMedia.Current.TakePhotoAsync (new Plugin.Media.Abstractions.StoreCameraMediaOptions {
Directory = "../Library",
Name = ImageFilename
});
然后为了获得方向,
var exifInterface = new ExifInterface (image.Path);
int orientation = exifInterface.GetAttributeInt (ExifInterface.TagOrientation, 0);
但是如果我检查方向,那么它总是 0。
我还在 exifInterface.GetAttributeInt 中传递了 -1,但它也给出了 0。
有人遇到过这样的问题吗?还是我在这里做错了什么?
您使用什么版本的
CrossMedia
? 2.4.0-beta1 中修复了类似问题
您使用的是什么设备?有些设备自然是横向的(例如三星 Galaxy Tab S4),这可能会导致图像的方向和当前旋转问题。
Xamarin.Forms: Rotate Image After Taking Photo
There are two approaches to rotate an image captured with the camera in Xamarin.Forms, depending on your preference:
1. Using CrossMedia Plugin (Simple):
If you're using the CrossMedia plugin for capturing photos, you can leverage the StoreCameraMediaOptions object within the TakePhotoAsync method. Set the RotateImage property to true to automatically rotate the captured image:
var storeOptions = new StoreCameraMediaOptions
{
RotateImage = true,
// Other options...
};
var result = await CrossMedia.Current.TakePhotoAsync(storeOptions);
2. Using MediaPicker and Exif (More Control):
This approach offers finer control over image rotation. It involves:
MediaPicker: Used to capture the photo in Xamarin.Forms.
ExifInterface (AndroidX.ExifInterface.Media NuGet): Reads the image's orientation data on Android. (Important: Use the AndroidX library, not the older Android.Media version)
SkiaSharp (Latest NuGet): Rotates the image based on the orientation data.
Steps:
a. Android Implementation (using DependencyService):
public int GetImageRotationAngle(Stream stream)
{
try
{
var exif = new ExifInterface(stream);
int orientation = exif.GetAttributeInt(ExifInterface.TagOrientation, ExifInterface.OrientationUndefined);
switch (orientation)
{
case ExifInterface.OrientationRotate90:
return 90;
case ExifInterface.OrientationRotate180:
return 180;
case ExifInterface.OrientationRotate270:
return 270;
default:
return 0;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in GetImageRoatation -> {ex}");
return 0;
}
}
b. Shared Code Implementation:
var photo = await MediaPicker.CapturePhotoAsync();
await LoadPhotoAsync(photo, path); // Replace 'path' with image file path
async Task LoadPhotoAsync(FileResult photo, string path)
{
try
{
using (var stream = await photo.OpenReadAsync())
{
using (var fileStream = File.Open(path, FileMode.OpenOrCreate))
{
var RIS = DependencyService.Get<IImageRotator>();
var rotationAngle = RIS.GetImageRotationAngle(stream);
var finalStream = await photo.OpenReadAsync();
if (rotationAngle > 0)
{
var bitmap = SKBitmap.Decode(finalStream);
SKBitmap photoBitmap = RotateBitmap(bitmap, rotationAngle);
Stream rotatedStream = SKImage.FromBitmap(photoBitmap).Encode().AsStream();
rotatedStream.CopyTo(fileStream);
rotatedStream.Flush();
return;
}
finalStream.CopyTo(fileStream);
finalStream.Flush();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in LoadPhotoAsync() => {ex}");
}
}
private SKBitmap RotateBitmap(SKBitmap bitmap, float angle)
{
SKBitmap rotatedBitmap = new SKBitmap(bitmap.Height, bitmap.Width);
using (var surface = new SKCanvas(rotatedBitmap))
{
surface.Translate(rotatedBitmap.Width, 0);
surface.RotateDegrees(angle);
surface.DrawBitmap(bitmap, 0, 0);
}
return rotatedBitmap;
}
c. Interface for DependencyService (optional):
public interface IImageRotator
{
int GetImageRotationAngle(Stream stream);
}
Finally,
The CrossMedia plugin offers a simpler solution, while the MediaPicker and Exif approach provides more control over the rotation process.