如何在iOS平台的.NET MAUI(C#)中为JPEG添加EXIF GPS数据
在.NET MAUI iOS平台为JPEG图片添加GPS EXIF数据的可行方案
方案1:使用SkiaSharp跨平台处理EXIF
SkiaSharp是谷歌Skia图形库的.NET绑定,支持跨平台读写EXIF元数据,MAUI项目可直接集成,无需区分平台编写过多原生代码。
步骤:
- 安装NuGet包:
SkiaSharp和SkiaSharp.NativeAssets.iOS(iOS平台需额外安装原生资产包) - 编写读写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框架,直接操作图片元数据。
步骤:
- 在MAUI项目的
Platforms/iOS目录下编写原生实现代码 - 通过依赖服务在共享代码中调用
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
相关产品推荐
相关产品推荐

