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

C# MAUI iOS平台为UIImage添加GPS元数据并保存问题求助

在iOS平台的C# MAUI应用中为UIImage添加GPS元数据并保存的解决方案

你遇到的Incorrect number or types of arguments错误,根源在于两个问题:一是元数据用了不可变的NSDictionary导致无法正确添加GPS字段,二是CGImageDestination.AddImage的参数类型使用错误。下面是修正后的完整实现方案:

核心错误修正点

  1. 元数据容器需用可变字典:NSDictionary是不可变对象,无法动态添加键值对,必须改用NSMutableDictionary来构建GPS元数据和主元数据字典。
  2. AddImage方法参数正确传递:该方法接受的是NSDictionary类型的元数据,而非CGImageDestinationOptions,直接传入构建好的元数据字典即可。

修正后的完整代码

替换你原代码中保存图片的逻辑,同时优化位置获取的异步逻辑(避免同步获取Location为空的问题):

public class ScreenshotService : IScreenshotService
{
    // 保留你原有的字段定义
    public byte[] imageArray { get; set; }
    public int width { get; set; }
    public int height { get; set; }
    public bool serviceLock { get; set; }
    private string fileName = "";
    public Location location { get; set; }

    public async Task<byte[]> CaptureAsync(View view)
    {
        byte[] resultBytes = null;
        await MainThread.InvokeOnMainThreadAsync(async () =>
        {
            try
            {
                Permission();
                // 保留你原有的图片合成逻辑
                var imageArgb = ConvertRgbaToArgb(imageArray, height, width);
                CGDataProvider dataProvider = new CGDataProvider(imageArgb, 0, imageArgb.Length);
                CGImage cgImage = new CGImage(width, height, 8, 32, width * 4, CGColorSpace.CreateDeviceRGB(), CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Big, dataProvider, null, false, CGColorRenderingIntent.Default);
                UIImage imageBase = new UIImage(cgImage);
                var handler = view.Handler as IPlatformViewHandler;
                var nativeView = handler?.PlatformView as UIView;
                if (nativeView == null) return;
                var size = nativeView.Bounds.Size;
                UIGraphics.BeginImageContextWithOptions(size, false, 0);
                var context = UIGraphics.GetCurrentContext();
                nativeView.Layer.RenderInContext(context);
                var imageOverlay = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                UIGraphics.BeginImageContextWithOptions(imageBase.Size, false, 0.0f);
                imageBase.Draw(new CGRect(0, 0, imageBase.Size.Width, imageBase.Size.Height));
                imageOverlay.Draw(new CGRect(0, 0, imageBase.Size.Width, imageBase.Size.Height));
                UIImage resultImage = UIGraphics.GetImageFromCurrentImageContext();
                UIGraphics.EndImageContext();
                SetupOutputFileName();

                // ------------------------ 修正后的带GPS元数据保存逻辑 ------------------------
                var locationManager = new CLLocationManager();
                // 请求位置授权
                locationManager.RequestWhenInUseAuthorization();
                // 检查授权状态
                var authStatus = CLLocationManager.Status;
                if (authStatus != CLAuthorizationStatus.AuthorizedWhenInUse && authStatus != CLAuthorizationStatus.AuthorizedAlways)
                {
                    Console.WriteLine("位置权限未授权");
                    return;
                }

                // 异步获取当前位置(避免同步获取为空)
                TaskCompletionSource<CLLocation> tcs = new TaskCompletionSource<CLLocation>();
                EventHandler<CLLocationUpdatedEventArgs> locationUpdatedHandler = (s, e) =>
                {
                    tcs.TrySetResult(e.Location);
                    locationManager.LocationsUpdated -= locationUpdatedHandler;
                };
                locationManager.LocationsUpdated += locationUpdatedHandler;
                locationManager.StartUpdatingLocation();
                CLLocation currentLocation = await tcs.Task;
                locationManager.StopUpdatingLocation();

                if (currentLocation != null)
                {
                    // 创建可变的GPS元数据字典
                    var gpsMetadata = new NSMutableDictionary();
                    gpsMetadata[CGImageProperties.GPSLatitude] = NSNumber.FromDouble(Math.Abs(currentLocation.Coordinate.Latitude));
                    gpsMetadata[CGImageProperties.GPSLatitudeRef] = new NSString(currentLocation.Coordinate.Latitude >= 0 ? "N" : "S");
                    gpsMetadata[CGImageProperties.GPSLongitude] = NSNumber.FromDouble(Math.Abs(currentLocation.Coordinate.Longitude));
                    gpsMetadata[CGImageProperties.GPSLongitudeRef] = new NSString(currentLocation.Coordinate.Longitude >= 0 ? "E" : "W");
                    // 可选:添加拍摄时间元数据
                    gpsMetadata[CGImageProperties.GPSTimeStamp] = new NSString(currentLocation.Timestamp.ToString("yyyy:MM:dd HH:mm:ss"));

                    // 创建主元数据字典
                    var metadata = new NSMutableDictionary();
                    metadata[CGImageProperties.GPSDictionary] = gpsMetadata;

                    // 保存带元数据的图片
                    var imageData = resultImage.AsJPEG();
                    var uti = UTType.JPEG.Identifier;
                    var destinationData = new NSMutableData();

                    using (var destination = CGImageDestination.Create(destinationData, uti, 1))
                    {
                        // 正确传递CGImage和元数据字典
                        destination.AddImage(resultImage.CGImage, metadata);
                        if (!destination.Close())
                        {
                            Console.WriteLine("CGImageDestination关闭失败");
                        }
                    }

                    // 写入文件
                    NSError error;
                    bool saveSuccess = destinationData.Save(fileName, false, out error);
                    if (!saveSuccess || error != null)
                    {
                        Console.WriteLine($"保存图片失败: {error?.LocalizedDescription ?? "未知错误"}");
                    }
                    else
                    {
                        resultBytes = destinationData.ToArray();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"捕获异常: {ex.Message}");
            }
        });
        return resultBytes;
    }

    // 保留你原有的Permission()、ConvertRgbaToArgb()、SetupOutputFileName()方法
}

额外注意事项

  1. 权限配置:在iOS项目的Info.plist中添加位置权限描述,否则授权会被拒绝:
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要访问你的位置以给照片添加地理标签</string>
  1. GPS字段规范:GPS纬度和经度需要存储绝对值,配合LatitudeRef和LongitudeRef区分南北纬、东西经,这是EXIF标准的强制要求。
  2. 位置获取可靠性:同步获取locationManager.Location大概率为空,因为位置更新是异步操作,用TaskCompletionSource监听事件能保证获取到有效位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:58:10