.NET MAUI中如何旋转ImageSource并保存到设备?
.NET MAUI 旋转ImageSource并保存到设备的实现方案
一、准备工作
先安装SkiaSharp相关NuGet包:SkiaSharp.Views.Maui.ControlsSkiaSharp.NativeAssets.Android(Android平台)SkiaSharp.NativeAssets.iOS(iOS平台)
二、旋转ImageSource的实现
核心思路
ImageSource是抽象类,无法直接操作像素。需先将其转换为SKBitmap(SkiaSharp位图对象),完成旋转后再转回ImageSource。
代码示例
using SkiaSharp; using System.IO; using Microsoft.Maui.Graphics; public static class ImageHelper { // 旋转ImageSource,rotationAngle为旋转角度(如90、180、270) public static async Task<ImageSource> RotateImageSourceAsync(ImageSource source, float rotationAngle) { StreamImageSource streamSource; if (source is not StreamImageSource tempSource) { // 非Stream类型的ImageSource先转成StreamImageSource streamSource = await ConvertToStreamImageSourceAsync(source); } else { streamSource = tempSource; } using var stream = await streamSource.Stream(CancellationToken.None); using var originalBitmap = SKBitmap.Decode(stream); // 计算旋转后的画布尺寸 var rotatedWidth = rotationAngle % 180 == 0 ? originalBitmap.Width : originalBitmap.Height; var rotatedHeight = rotationAngle % 180 == 0 ? originalBitmap.Height : originalBitmap.Width; // 创建旋转后的位图并绘制 using var rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight); using var canvas = new SKCanvas(rotatedBitmap); canvas.Translate(rotatedWidth / 2f, rotatedHeight / 2f); canvas.RotateDegrees(rotationAngle); canvas.Translate(-originalBitmap.Width / 2f, -originalBitmap.Height / 2f); canvas.DrawBitmap(originalBitmap, 0, 0); // 将旋转后的位图转成Stream,再封装为ImageSource using var ms = new MemoryStream(); rotatedBitmap.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms); ms.Position = 0; return ImageSource.FromStream(() => ms); } // 辅助方法:将任意ImageSource转成StreamImageSource private static async Task<StreamImageSource> ConvertToStreamImageSourceAsync(ImageSource source) { if (source is FileImageSource fileSource) { var stream = File.OpenRead(fileSource.File); return ImageSource.FromStream(() => stream) as StreamImageSource; } else if (source is UriImageSource uriSource) { using var client = new HttpClient(); var stream = await client.GetStreamAsync(uriSource.Uri); var memoryStream = new MemoryStream(); await stream.CopyToAsync(memoryStream); memoryStream.Position = 0; return ImageSource.FromStream(() => memoryStream) as StreamImageSource; } throw new NotSupportedException("不支持的ImageSource类型"); } }
三、将处理后的ImageSource保存到设备
核心思路
把旋转后的ImageSource转成Stream,再通过MAUI的FileSystem类写入设备存储(应用私有目录或公共图库)。
代码示例
using System.IO; using Microsoft.Maui.Storage; public static class ImageSaver { // 保存到应用私有目录 public static async Task<string> SaveToAppDirectoryAsync(ImageSource source, string fileName) { var streamSource = await ImageHelper.ConvertToStreamImageSourceAsync(source); using var stream = await streamSource.Stream(CancellationToken.None); var directoryPath = FileSystem.AppDataDirectory; var filePath = Path.Combine(directoryPath, fileName); using var fileStream = File.Create(filePath); await stream.CopyToAsync(fileStream); return filePath; } // 保存到公共图库(需配置平台权限) public static async Task SaveToGalleryAsync(ImageSource source, string fileName) { var streamSource = await ImageHelper.ConvertToStreamImageSourceAsync(source); using var stream = await streamSource.Stream(CancellationToken.None); // 先写入缓存目录,再通过MediaPicker保存到图库 var cachePath = Path.Combine(FileSystem.CacheDirectory, fileName); using var cacheStream = File.Create(cachePath); await stream.CopyToAsync(cacheStream); await MediaPicker.Default.SavePhotoAsync(new MediaPickerSavePhotoOptions { FileName = fileName, SaveToAlbum = true }); } }
四、平台权限配置
Android
在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
iOS
在Info.plist中添加:
<key>NSPhotoLibraryAddUsageDescription</key> <string>需要访问相册保存图片</string>
五、使用示例
// 原始图片源 var originalImage = ImageSource.FromFile("test.jpg"); // 旋转90度 var rotatedImage = await ImageHelper.RotateImageSourceAsync(originalImage, 90); // 保存到应用私有目录 var savedPath = await ImageSaver.SaveToAppDirectoryAsync(rotatedImage, "rotated_test.jpg"); // 保存到公共图库 await ImageSaver.SaveToGalleryAsync(rotatedImage, "rotated_test.jpg");
内容的提问来源于stack exchange,提问作者LeandroTheDev
相关产品推荐
相关产品推荐

