WinUI 3中移除BitmapImage的黑色背景
WinUI 3中移除BitmapImage的黑色背景
作为首次开发桌面应用的开发者,我完全理解你现在的困扰——WinUI 3里的BitmapImage是专为显示优化的,和传统.NET里的Bitmap操作逻辑差异很大,而且WriteableBitmap的像素操作确实容易踩坑。下面给你两个实用的方案,帮你把扫描PNG里的黑色背景转成透明:
方案一:用Win2D处理(推荐,更简洁高效)
Win2D是微软官方的2D图形库,在WinUI 3里处理图像特效非常方便。首先你需要在项目里安装Win2D.uwp这个NuGet包,然后用颜色替换效果来把黑色转为透明:
using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Effects; using Windows.Storage; using Windows.Storage.Streams; // 假设back是你的图片文件路径 async void ProcessImageWithWin2D(string back) { try { // 从路径获取图片文件 StorageFile file = await StorageFile.GetFileFromPathAsync(back); using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { // 初始化Win2D设备和加载图片 CanvasDevice device = CanvasDevice.GetSharedDevice(); CanvasBitmap canvasBitmap = await CanvasBitmap.LoadAsync(device, stream); // 创建用于处理的渲染目标 CanvasRenderTarget renderTarget = new CanvasRenderTarget( device, canvasBitmap.SizeInPixels.Width, canvasBitmap.SizeInPixels.Height, canvasBitmap.Dpi); using (CanvasDrawingSession ds = renderTarget.CreateDrawingSession()) { // 配置颜色替换效果:把黑色换成透明 var colorReplaceEffect = new ColorReplaceEffect() { Source = canvasBitmap, OldColor = Windows.UI.Colors.Black, NewColor = Windows.UI.Colors.Transparent, Tolerance = 0.1f // 容差可以调整,数值越大越能处理接近黑色的暗像素 }; // 绘制处理后的图像 ds.DrawImage(colorReplaceEffect); } // 把处理后的图像转成BitmapImage显示 BitmapImage processedImage = new BitmapImage(); using (var renderStream = new InMemoryRandomAccessStream()) { await renderTarget.SaveAsync(renderStream, CanvasBitmapFileFormat.Png); renderStream.Seek(0); await processedImage.SetSourceAsync(renderStream); } this.Front.Source = processedImage; } } catch (Exception ex) { // 这里可以加异常处理,比如提示用户加载失败 System.Diagnostics.Debug.WriteLine($"处理图片出错:{ex.Message}"); } }
方案二:用WriteableBitmap手动操作像素
如果你不想引入额外库,可以直接解码图片像素,手动把黑色像素的Alpha通道设为0(透明)。之前你说用不了CopyPixel(),大概率是因为BitmapImage是只读的,没法直接获取像素,所以我们需要先解码图片拿到原始像素数据:
using Windows.Graphics.Imaging; using Windows.Storage; using Windows.Storage.Streams; async void ProcessImageWithWriteableBitmap(string back) { try { StorageFile file = await StorageFile.GetFileFromPathAsync(back); using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { // 解码图片获取像素数据 BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); PixelDataProvider pixelData = await decoder.GetPixelDataAsync( BitmapPixelFormat.Bgra8, // 用BGRA格式,每个像素4字节 BitmapAlphaMode.Straight, new BitmapTransform(), ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); byte[] pixels = pixelData.DetachPixelData(); uint width = decoder.PixelWidth; uint height = decoder.PixelHeight; int bytesPerPixel = 4; // 遍历所有像素,把接近黑色的像素设为透明 for (int i = 0; i < pixels.Length; i += bytesPerPixel) { // BGRA格式:索引0=蓝,1=绿,2=红,3=Alpha byte blue = pixels[i]; byte green = pixels[i + 1]; byte red = pixels[i + 2]; // 判断是否是黑色(可以调整阈值,比如RGB都小于20就认为是黑色) if (red < 20 && green < 20 && blue < 20) { pixels[i + 3] = 0; // 设置Alpha为0,完全透明 } } // 创建WriteableBitmap并写入处理后的像素 WriteableBitmap wb = new WriteableBitmap((int)width, (int)height); using (Stream pixelStream = wb.PixelBuffer.AsStream()) { await pixelStream.WriteAsync(pixels, 0, pixels.Length); } // 显示处理后的图片 this.Front.Source = wb; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"处理图片出错:{ex.Message}"); } }
小提示
扫描的图片往往不会是纯黑背景,可能带一些灰色噪点,所以你可以调整方案里的阈值(比如把20改成30),这样能把更多暗色调的背景都转成透明,效果会更好。
备注:内容来源于stack exchange,提问作者Queen Mochi
相关产品推荐
相关产品推荐

