ios MediaPicker.CapturePhotoAsync()图像旋转90度

62o28rlo  于 11个月前  发布在  iOS
关注(0)|答案(2)|浏览(119)

当我用下面的代码捕捉照片时,我会在AndroidiOS中将保存的照片旋转90度
有没有解决这个问题的办法?所以我得到保存的图像方向调整正确

FileResult photo = await MediaPicker.CapturePhotoAsync();
using Stream sourceStream = await photo.OpenReadAsync();
var picture = PlatformImage.FromStream(sourceStream);

string localFilePath = $"{FileSystem.CacheDirectory}/{photo.FileName}";
using FileStream localFileStream = File.OpenWrite(localFilePath);
await picture.SaveAsync(localFileStream, ImageFormat.Jpeg, quality: 0.90f);

字符串

dffbzjpn

dffbzjpn1#

保存源流的字节直接保存到文件流。
不要使用中间图片。

e5nszbig

e5nszbig2#

我处理这个问题的方法是在iOS和Android上实现我自己的CapturePhotoAsync,这样图像总是以正确的方式返回(使用这个线程上的一些代码:https://github.com/xamarin/Essentials/issues/1514)。然后我可以很高兴地使用PlatformImage.FromStream,因为我知道当我丢失exif数据时,图像已经是正确的方式了。一旦他们解决了这个问题,它也应该最大限度地减少更改。
我创建了以下接口:

public interface IImageService
{
    Task<FileResult> CapturePhotoAsync(MediaPickerOptions options = null);
}

字符串
然后在我创建的Platforms/Android目录下:

using Android.Graphics;
using AndroidX.ExifInterface.Media;
using Microsoft.Extensions.Logging;
using Path = System.IO.Path;
using Stream = System.IO.Stream;

namespace CaptureImageFix
{
    public enum ImageOrientation
    {
        Undefined = 0,
        Normal = 1,
        FlipHorizontal = 2,
        Rotate180 = 3,
        FlipVertical = 4,
        Transpose = 5,
        Rotate90 = 6,
        Transverse = 7,
        Rotate270 = 8
    }
    public partial class ImageService : IImageService
    {
        private readonly ILogger<ImageService> _logger;

        public ImageService(ILogger<ImageService> logger)
        {
            _logger = logger;
        }

        public async Task<FileResult> CapturePhotoAsync(MediaPickerOptions options = null)
        {
            var fileResult = await MediaPicker.Default.CapturePhotoAsync(options);
            if (fileResult == null)
                return null;
            await using var stream = await fileResult.OpenReadAsync();
            stream.Position = 0;
            var orientation = GetImageOrientation(stream);
            stream.Position = 0;
            var originalBitmap = await BitmapFactory.DecodeStreamAsync(stream);
            var matrix = new Matrix();
            switch (orientation)
            {
                case ImageOrientation.Normal:
                    break;
                case ImageOrientation.FlipHorizontal:
                    break;
                case ImageOrientation.Rotate180:
                    break;
                case ImageOrientation.FlipVertical:
                    matrix.PreRotate(180);
                    break;
                case ImageOrientation.Transpose:
                    matrix.PreRotate(90);
                    break;
                case ImageOrientation.Rotate90:
                    matrix.PreRotate(90);
                    break;
                case ImageOrientation.Transverse:
                    matrix.PreRotate(-90);
                    break;
                case ImageOrientation.Rotate270:
                    matrix.PreRotate(-90);
                    break;
            }
            var normalizedBitmap = Bitmap.CreateBitmap(
                originalBitmap, 
                0, 
                0, 
                originalBitmap.Width, 
                originalBitmap.Height, 
                matrix, 
                true);
            using var outStream = new MemoryStream();
            await normalizedBitmap.CompressAsync(Bitmap.CompressFormat.Jpeg, 100, outStream);
            outStream.Position = 0;
            var jpegFilename = Path.Combine(FileSystem.CacheDirectory, $"{Guid.NewGuid()}.jpg");
            await File.WriteAllBytesAsync(jpegFilename, outStream.ToArray());
            return new FileResult(jpegFilename);
        }

        private ImageOrientation GetImageOrientation(Stream stream)
        {
            var exif = new ExifInterface(stream);
            var tag = exif.GetAttribute(ExifInterface.TagOrientation);
            var orientation = string.IsNullOrEmpty(tag) ?
                ImageOrientation.Undefined :
                (ImageOrientation)Enum.Parse(typeof(ImageOrientation), tag);
            exif.Dispose();

            return orientation;
        }
    }
}


在我创建的Platforms/iOS目录下(注意,这两个都是分部类,必须在同一个命名空间中):

using Microsoft.Extensions.Logging;
using Microsoft.Maui.Graphics.Platform;
using MobileCoreServices;
using UIKit;

namespace CaptureImageFix
{
    public partial class ImageService : IImageService
    {
        private readonly ILogger<ImageService> _logger;

        public ImageService(ILogger<ImageService> logger)
        {
            _logger = logger;
        }

        public async Task<FileResult> CapturePhotoAsync(MediaPickerOptions options = null)
        {
            return await MainThread.InvokeOnMainThreadAsync(async () =>
                await InternalCapturePhotoAsync(options));
        }

        private async Task<FileResult> InternalCapturePhotoAsync(MediaPickerOptions options)
        {
            var taskCompletionSource = new TaskCompletionSource<FileResult>();
            if (await Permissions.RequestAsync<Permissions.Camera>() == PermissionStatus.Granted)
            {
                var imagePicker = new UIImagePickerController
                {
                    SourceType = UIImagePickerControllerSourceType.Camera,
                    MediaTypes = new string[] { UTType.Image }
                };

                if (!string.IsNullOrEmpty(options?.Title))
                {
                    imagePicker.Title = options.Title;
                }

                var viewController = Platform.GetCurrentUIViewController();

                imagePicker.AllowsEditing = false;
                imagePicker.FinishedPickingMedia += async (sender, e) =>
                {
                    var jpegFilename = Path.Combine(FileSystem.CacheDirectory, $"{Guid.NewGuid()}.jpg");
                    var uiImage = e.Info[UIImagePickerController.OriginalImage] as UIImage;
                    var normalizedImage = uiImage.NormalizeOrientation();
                    var normalizedData = normalizedImage.AsJPEG(new nfloat(1));
                    await viewController.DismissViewControllerAsync(true);
                    if (normalizedData.Save(jpegFilename, false, out var error))
                    {
                        taskCompletionSource.TrySetResult(new FileResult(jpegFilename));
                    }
                    else
                    {
                        taskCompletionSource.TrySetException(new Exception($"Error saving the image: {error}"));
                    }
                    imagePicker?.Dispose();
                    imagePicker = null;
                };

                imagePicker.Canceled += async (sender, e) =>
                {
                    await viewController.DismissViewControllerAsync(true);
                    taskCompletionSource.TrySetResult(null);
                    imagePicker?.Dispose();
                    imagePicker = null;
                };

                await viewController.PresentViewControllerAsync(imagePicker, true);
            }
            else
            {
                taskCompletionSource.TrySetResult(null);
                taskCompletionSource.TrySetException(new PermissionException("Camera permission not granted"));
            }

            return await taskCompletionSource.Task;
        }
    }
}


然后在MauiProgram.cs文件中添加以下内容:

builder.Services.AddTransient<IImageService, ImageService>();


然后,您可以注入IImageService并使用它来拾取图像。
每个实现都克服了MAUI提供的MediaPicker.Default.CapturePhotoAsync的本机实现的特定问题:

*iOS。MAUI实现返回一个已剥离exif数据且未校正图像的PNG。上述实现创建自己的UIImagePickerController示例并检索图像,校正图像,将其保存为jpeg,然后返回指向该JPEG的FileResult
*Android. MAUI实现返回一个包含exif数据的JPEG,但是当调用PlatformImage.FromStream时,它会丢失该数据,因此为了消除这种影响,上面的实现 Package 了对MediaPicker.Default.CapturePhotoAsync的调用,然后使用exif数据创建一个新的文件更正版本。

相关问题