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

如何在iOS平台的.NET MAUI(C#)中为JPEG添加EXIF GPS数据

在.NET MAUI iOS平台为JPEG图片添加GPS EXIF数据的可行方案

方案1:使用SkiaSharp跨平台处理EXIF

SkiaSharp是谷歌Skia图形库的.NET绑定,支持跨平台读写EXIF元数据,MAUI项目可直接集成,无需区分平台编写过多原生代码。

步骤:

  1. 安装NuGet包:SkiaSharp 和 SkiaSharp.NativeAssets.iOS(iOS平台需额外安装原生资产包)
  2. 编写读写EXIF的代码:
using SkiaSharp;

public void AddGpsExifToJpeg(string inputImagePath, string outputImagePath, double latitude, double longitude, double altitude = 0)
{
    // 读取原始JPEG图片
    using var inputStream = File.OpenRead(inputImagePath);
    using var originalBitmap = SKBitmap.Decode(inputStream);
    
    // 初始化EXIF元数据容器
    var exifData = new SKExifMetadata();
    
    // 处理GPS纬度:转换为度分秒格式,设置南北方向
    var latAbs = Math.Abs(latitude);
    var latDegrees = (int)latAbs;
    var latMinutes = (int)((latAbs - latDegrees) * 60);
    var latSeconds = (latAbs - latDegrees - latMinutes / 60.0) * 3600;
    exifData.SetGpsLatitude(latDegrees, latMinutes, latSeconds, 
        latitude >= 0 ? SKExifLatitudeLongitude.North : SKExifLatitudeLongitude.South);
    
    // 处理GPS经度:转换为度分秒格式,设置东西方向
    var lonAbs = Math.Abs(longitude);
    var lonDegrees = (int)lonAbs;
    var lonMinutes = (int)((lonAbs - lonDegrees) * 60);
    var lonSeconds = (lonAbs - lonDegrees - lonMinutes / 60.0) * 3600;
    exifData.SetGpsLongitude(lonDegrees, lonMinutes, lonSeconds, 
        longitude >= 0 ? SKExifLatitudeLongitude.East : SKExifLatitudeLongitude.West);
    
    // 设置海拔信息(可选)
    exifData.GpsAltitude = altitude;
    exifData.GpsAltitudeRef = altitude >= 0 ? SKExifAltitudeReference.SeaLevel : SKExifAltitudeReference.BelowSeaLevel;
    
    // 先编码图片为JPEG,再写入EXIF数据
    using var outputStream = File.OpenWrite(outputImagePath);
    var encodedImage = originalBitmap.Encode(SKEncodedImageFormat.Jpeg, 90);
    encodedImage.SaveTo(outputStream);
    
    // 将EXIF数据追加到输出文件
    using var outputFileStream = SKFileWStream.Open(outputImagePath);
    var exifWriter = new SKExifWriter(outputFileStream);
    exifWriter.Write(exifData);
}

方案2:调用iOS原生ImageIO框架(平台特定代码)

如果需要更贴近iOS原生的处理逻辑,可通过MAUI的平台特定代码调用ImageIO框架,直接操作图片元数据。

步骤:

  1. 在MAUI项目的Platforms/iOS目录下编写原生实现代码
  2. 通过依赖服务在共享代码中调用

1. 定义共享接口

在共享项目中创建接口:

public interface IExifGpsService
{
    void AddGpsToJpeg(string inputPath, string outputPath, double latitude, double longitude);
}

2. iOS平台实现接口

在Platforms/iOS下创建实现类:

using Foundation;
using ImageIO;
using CoreGraphics;
using System.IO;
using Microsoft.Maui.Controls;

[assembly: Dependency(typeof(ExifGpsServiceIos))]
namespace YourAppNamespace.Platforms.iOS;

public class ExifGpsServiceIos : IExifGpsService
{
    public void AddGpsToJpeg(string inputPath, string outputPath, double latitude, double longitude)
    {
        var inputUrl = NSUrl.FromFilename(inputPath);
        var imageSource = CGImageSource.Create(inputUrl, null);
        
        // 获取原始图片属性并转为可变字典
        var originalProps = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, null);
        var mutableProps = new NSMutableDictionary(originalProps);
        
        // 构建GPS元数据字典
        var gpsDict = new NSMutableDictionary();
        
        // 处理纬度
        var latAbs = Math.Abs(latitude);
        gpsDict.SetValueForKey(NSNumber.FromInt32((int)latAbs), CGImageProperties.GPSLatitudeDegrees);
        gpsDict.SetValueForKey(NSNumber.FromInt32((int)((latAbs - (int)latAbs) * 60)), CGImageProperties.GPSLatitudeMinutes);
        gpsDict.SetValueForKey(NSNumber.FromDouble((latAbs - (int)latAbs - ((int)((latAbs - (int)latAbs) * 60))/60.0) * 3600), CGImageProperties.GPSLatitudeSeconds);
        gpsDict.SetValueForKey(new NSString(latitude >= 0 ? "N" : "S"), CGImageProperties.GPSLatitudeRef);
        
        // 处理经度
        var lonAbs = Math.Abs(longitude);
        gpsDict.SetValueForKey(NSNumber.FromInt32((int)lonAbs), CGImageProperties.GPSLongitudeDegrees);
        gpsDict.SetValueForKey(NSNumber.FromInt32((int)((lonAbs - (int)lonAbs) * 60)), CGImageProperties.GPSLongitudeMinutes);
        gpsDict.SetValueForKey(NSNumber.FromDouble((lonAbs - (int)lonAbs - ((int)((lonAbs - (int)lonAbs) * 60))/60.0) * 3600), CGImageProperties.GPSLongitudeSeconds);
        gpsDict.SetValueForKey(new NSString(longitude >= 0 ? "E" : "W"), CGImageProperties.GPSLongitudeRef);
        
        // 将GPS字典加入图片属性
        mutableProps.SetValueForKey(gpsDict, CGImageProperties.GPSDictionary);
        
        // 写入带GPS信息的图片
        var outputUrl = NSUrl.FromFilename(outputPath);
        var imageDest = CGImageDestination.Create(outputUrl, CGImageSourceGetType(imageSource), 1, null);
        CGImageDestinationAddImageFromSource(imageDest, imageSource, 0, mutableProps);
        
        if (!CGImageDestinationFinalize(imageDest))
        {
            throw new IOException("写入带GPS EXIF的图片失败");
        }
    }
}

3. 在共享代码中调用

var exifService = DependencyService.Get<IExifGpsService>();
// 示例:给图片添加北京的GPS坐标
exifService.AddGpsToJpeg("/path/to/input.jpg", "/path/to/output.jpg", 39.9042, 116.4074);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 22:08:15