SkiaSharp绘制Bitmap仅显示空白的问题求助
问题
我想从SKBitmap中裁剪一部分内容绘制到新Bitmap中,再转成byte[]发送给后端。参考了微软SkiaSharp教程,但不需要显示Canvas,只需要获取新Bitmap。直接转换原图片为byte[]能正常得到可上传的图片,但用Canvas绘制后得到的是空白内容,就算复制原Bitmap再绘制也还是空白。相关代码如下:
C#逻辑代码
public async void UploadImage() { FileResult im = await FilePicker.PickAsync(new PickOptions() { FileTypes = FilePickerFileType.Images, }); byte[] bytes = null; using (Stream ms = await im.OpenReadAsync()) { bytes = new byte[ms.Length]; ms.Read(bytes, 0, bytes.Length); } SKBitmap sourceMap = null; using (MemoryStream stream = new MemoryStream(bytes)) { sourceMap = SKBitmap.Decode(stream); } //SKBitmap destination = new SKBitmap(sourceMap.Width,sourceMap.Height); SKBitmap destination = sourceMap.Copy(); SKRect dest = new SKRect(sourceMap.Height / 4, sourceMap.Height / 4, sourceMap.Width / 4, -sourceMap.Height / 4); SKRect source = new SKRect(sourceMap.Height/4,sourceMap.Height/4,sourceMap.Width/4,-sourceMap.Height/4); using (SKCanvas canvas = new SKCanvas(destination)) { canvas.Clear(); canvas.DrawBitmap(sourceMap, source, dest); } SKImage skImage = SKImage.FromBitmap(destination); SKData encoded = skImage.Encode(); using(MemoryStream memory = new MemoryStream()) { encoded.AsStream().CopyTo(memory); Image = memory.ToArray(); } }
视图代码
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:ImageCroppingTry2="clr-namespace:ImageCroppingTry2" x:DataType="ImageCroppingTry2:MainPageViewModel" x:Class="ImageCroppingTry2.MainPage"> <ContentPage.Resources> <ResourceDictionary> <toolkit:ByteArrayToImageSourceConverter x:Key="ByteArrayToImageSourceConverter" /> </ResourceDictionary> </ContentPage.Resources> <VerticalStackLayout> <Image x:Name="displayImage" Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}"/> <Button Command="{Binding UploadImageCommand}"></Button> </VerticalStackLayout>
解决方案
你的问题核心是SKRect参数定义错误,以及目标Bitmap的使用逻辑不合理,以下是具体修复方案:
问题分析
- SKRect构造顺序错误:SKRect的正确参数顺序是
(left, top, right, bottom),要求right > left且bottom > top。你定义的source和dest矩形中,right小于left、bottom小于top,导致矩形无效,SkiaSharp会直接跳过绘制操作。 - 目标Bitmap尺寸不匹配:如果是要生成裁剪后的小图,目标Bitmap应该对应裁剪区域的尺寸;如果要在原尺寸画布上绘制,也必须保证矩形参数有效。
修正后的代码
C#逻辑代码
public async void UploadImage() { FileResult im = await FilePicker.PickAsync(new PickOptions() { FileTypes = FilePickerFileType.Images, }); byte[] bytes = null; using (Stream ms = await im.OpenReadAsync()) { bytes = new byte[ms.Length]; await ms.ReadAsync(bytes, 0, bytes.Length); // 改用异步读取更稳妥 } SKBitmap sourceMap = null; using (MemoryStream stream = new MemoryStream(bytes)) { sourceMap = SKBitmap.Decode(stream); } // 定义有效裁剪区域:从原图1/4位置开始,取1/2宽高的区域 float cropLeft = sourceMap.Width / 4f; float cropTop = sourceMap.Height / 4f; float cropRight = sourceMap.Width * 3 / 4f; float cropBottom = sourceMap.Height * 3 / 4f; SKRect sourceRect = new SKRect(cropLeft, cropTop, cropRight, cropBottom); // 根据裁剪区域尺寸创建目标Bitmap int destWidth = (int)(cropRight - cropLeft); int destHeight = (int)(cropBottom - cropTop); SKBitmap destination = new SKBitmap(destWidth, destHeight); using (SKCanvas canvas = new SKCanvas(destination)) { canvas.Clear(SKColors.Transparent); // 清空画布为透明(可按需改背景色) // 将裁剪区域绘制到目标Bitmap,填满整个新画布 canvas.DrawBitmap(sourceMap, sourceRect, new SKRect(0, 0, destWidth, destHeight)); } SKImage skImage = SKImage.FromBitmap(destination); SKData encoded = skImage.Encode(SKEncodedImageFormat.Png, 100); // 指定编码格式和质量 using (MemoryStream memory = new MemoryStream()) { encoded.AsStream().CopyTo(memory); Image = memory.ToArray(); } // 手动释放Bitmap资源,避免内存泄漏 sourceMap.Dispose(); destination.Dispose(); }
关键修改说明
- 修正SKRect参数,确保
left < right、top < bottom,定义有效的裁剪区域。 - 根据裁剪区域尺寸创建目标Bitmap,减少不必要的内存占用。
- 改用异步流读取,符合MAUI异步编程规范。
- 明确指定图片编码格式和质量,避免默认格式的不确定性。
- 添加资源释放逻辑,防止内存泄漏。
视图代码(仅优化按钮文本)
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:ImageCroppingTry2="clr-namespace:ImageCroppingTry2" x:DataType="ImageCroppingTry2:MainPageViewModel" x:Class="ImageCroppingTry2.MainPage"> <ContentPage.Resources> <ResourceDictionary> <toolkit:ByteArrayToImageSourceConverter x:Key="ByteArrayToImageSourceConverter" /> </ResourceDictionary> </ContentPage.Resources> <VerticalStackLayout> <Image x:Name="displayImage" Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}"/> <Button Command="{Binding UploadImageCommand}" Text="选择并裁剪图片"></Button> </VerticalStackLayout>
内容的提问来源于stack exchange,提问作者WoistdasNiveau
相关产品推荐
相关产品推荐

