You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Xamarin UWP镜像问题及禁用iOS前置摄像头

解决方案

UWP平台摄像头镜像问题处理

UWP平台下使用MediaPicker.CapturePhotoAsync()拍摄的照片出现镜像,是因为部分设备摄像头输出默认会做镜像处理,需手动对图像进行水平翻转修正:

在获取图片字节数组后,添加UWP专属的图像翻转逻辑:

#if WINDOWS_UWP
using Windows.UI.Xaml.Media.Imaging;
using Windows.Graphics.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;

// 基于获取到的imgByte进行镜像修正
var stream = new MemoryStream(imgByte).AsRandomAccessStream();
var decoder = await BitmapDecoder.CreateAsync(stream);

// 设置水平翻转的变换参数
var transform = new BitmapTransform();
transform.Flip = BitmapFlip.Horizontal;

// 获取翻转后的像素数据
var pixelData = await decoder.GetPixelDataAsync(
    BitmapPixelFormat.Bgra8,
    BitmapAlphaMode.Ignore,
    transform,
    ExifOrientationMode.RespectExifOrientation,
    ColorManagementMode.DoNotColorManage);

var pixels = pixelData.DetachPixelData();
var writeableBitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
await writeableBitmap.PixelBuffer.AsStream().WriteAsync(pixels, 0, pixels.Length);

// 将修正后的图像重新转为byte[]
using (var ms = new MemoryStream())
{
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ms.AsRandomAccessStream());
    encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
        (uint)writeableBitmap.PixelWidth, (uint)writeableBitmap.PixelHeight,
        decoder.DpiX, decoder.DpiY, pixels);
    await encoder.FlushAsync();
    imgByte = ms.ToArray();
}
#endif

iOS平台禁用前置摄像头

Xamarin.Essentials的MediaPicker没有直接提供禁用前置摄像头的API,需通过依赖服务自定义iOS拍照界面,强制锁定后置摄像头:

  1. 在共享项目中定义摄像头服务接口:
public interface ICameraService
{
    Task<byte[]> CaptureRearCameraPhotoAsync();
}
  1. 在iOS项目中实现该接口:
using UIKit;
using AVFoundation;
using Xamarin.Forms;
using CoreGraphics;

[assembly: Dependency(typeof(CameraService))]
namespace YourAppNamespace.iOS
{
    public class CameraService : ICameraService
    {
        private UIImagePickerController _picker;
        private TaskCompletionSource<byte[]> _tcs;

        public async Task<byte[]> CaptureRearCameraPhotoAsync()
        {
            _tcs = new TaskCompletionSource<byte[]>();

            _picker = new UIImagePickerController();
            _picker.SourceType = UIImagePickerControllerSourceType.Camera;
            _picker.CameraDevice = UIImagePickerControllerCameraDevice.Rear; // 强制使用后置摄像头
            _picker.ShowsCameraControls = true;
            _picker.Delegate = new CameraPickerDelegate(this);

            var window = UIApplication.SharedApplication.KeyWindow;
            var viewController = window.RootViewController;
            await viewController.PresentViewControllerAsync(_picker, true);

            return await _tcs.Task;
        }

        private class CameraPickerDelegate : UIImagePickerControllerDelegate
        {
            private readonly CameraService _service;

            public CameraPickerDelegate(CameraService service)
            {
                _service = service;
            }

            public override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info)
            {
                var image = info[UIImagePickerController.OriginalImage] as UIImage;
                // 修正iOS拍照默认的图像旋转问题
                image = image.FixOrientation();

                // 将图像转为byte[]
                using (var ms = new MemoryStream())
                {
                    var data = image.AsJPEG(0.8f);
                    data.CopyTo(ms);
                    _service._tcs.SetResult(ms.ToArray());
                }

                picker.DismissViewController(true, null);
            }

            public override void Canceled(UIImagePickerController picker)
            {
                _service._tcs.SetResult(null);
                picker.DismissViewController(true, null);
            }
        }
    }

    // 扩展方法:修正iOS图像旋转
    public static class UIImageExtensions
    {
        public static UIImage FixOrientation(this UIImage image)
        {
            if (image.Orientation == UIImageOrientation.Up)
                return image;

            var transform = CGAffineTransform.MakeIdentity();

            switch (image.Orientation)
            {
                case UIImageOrientation.Down:
                case UIImageOrientation.DownMirrored:
                    transform = CGAffineTransform.MakeTranslation(image.Size.Width, image.Size.Height);
                    transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI);
                    break;
                case UIImageOrientation.Left:
                case UIImageOrientation.LeftMirrored:
                    transform = CGAffineTransform.MakeTranslation(image.Size.Height, 0);
                    transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2);
                    break;
                case UIImageOrientation.Right:
                case UIImageOrientation.RightMirrored:
                    transform = CGAffineTransform.MakeTranslation(0, image.Size.Width);
                    transform = CGAffineTransform.Rotate(transform, -(nfloat)Math.PI / 2);
                    break;
            }

            switch (image.Orientation)
            {
                case UIImageOrientation.UpMirrored:
                case UIImageOrientation.DownMirrored:
                    transform = CGAffineTransform.Translate(transform, image.Size.Width, 0);
                    transform = CGAffineTransform.Scale(transform, -1, 1);
                    break;
                case UIImageOrientation.LeftMirrored:
                case UIImageOrientation.RightMirrored:
                    transform = CGAffineTransform.Translate(transform, image.Size.Height, 0);
                    transform = CGAffineTransform.Scale(transform, -1, 1);
                    break;
            }

            var context = new CGBitmapContext(IntPtr.Zero, (nint)image.Size.Width, (nint)image.Size.Height,
                image.CGImage.BitsPerComponent, image.CGImage.BytesPerRow, image.CGImage.ColorSpace,
                image.CGImage.BitmapInfo);

            context.ConcatCTM(transform);

            switch (image.Orientation)
            {
                case UIImageOrientation.Left:
                case UIImageOrientation.LeftMirrored:
                case UIImageOrientation.Right:
                case UIImageOrientation.RightMirrored:
                    context.DrawImage(new CGRect(0, 0, image.Size.Height, image.Size.Width), image.CGImage);
                    break;
                default:
                    context.DrawImage(new CGRect(0, 0, image.Size.Width, image.Size.Height), image.CGImage);
                    break;
            }

            var cgImage = context.ToImage();
            return new UIImage(cgImage);
        }
    }
}
  1. 在共享项目中替换原MediaPicker调用,改用依赖服务:
var cameraService = DependencyService.Get<ICameraService>();
var imgByte = await cameraService.CaptureRearCameraPhotoAsync();
if (imgByte == null)
{
    return;
}

内容的提问来源于stack exchange,提问作者Xamarin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:05:18