将字节数组转为Bitmap后调用EndInit()时出现System.NotSupportedException异常
问题分析与解决方案
核心错误原因
- 像素数组大小计算错误:你用
_originalImage.PixelWidth * stride计算总字节数,正确的应该是_originalImage.PixelHeight * stride——总像素行数是图像高度,每行字节数是stride,总大小是行数×每行字节数。 - 像素格式处理错误:WPF的
BitmapImage默认采用BGRA格式(每个像素占4字节:蓝、绿、红、透明度),你的循环按3字节步长处理,跳过了透明度通道,同时循环边界计算错误,会导致部分像素未处理或越界。 - BitmapImage的使用误区:
BitmapImage需要读取编码后的图像数据流(如PNG、JPG格式),但你直接把原始像素字节数组写入MemoryStream,这不是标准图像格式,所以初始化时会抛出异常。
修正后的代码
1. 修正ApplyFilter_Click方法的像素数组大小计算
private async void ApplyFilter_Click(object sender, RoutedEventArgs e) { int stride = _originalImage.PixelWidth * 4; // 修正:总大小 = 高度 × 每行字节数 long size = _originalImage.PixelHeight * stride; byte[] originalPixels = new byte[size]; _originalImage.CopyPixels(originalPixels, stride, 0); // 改用WriteableBitmap,直接处理原始像素 WriteableBitmap source = await ToBlackAndWhiteImage(originalPixels); ChangedImage.Source = source; }
2. 重写ToBlackAndWhiteImage方法,正确处理BGRA格式并返回WriteableBitmap
private Task<WriteableBitmap> ToBlackAndWhiteImage(byte[] originalPixels) { // 按BGRA格式循环,步长为4 for (int i = 0; i < originalPixels.Length; i += 4) { // 提取蓝、绿、红通道值 byte blue = originalPixels[i]; byte green = originalPixels[i + 1]; byte red = originalPixels[i + 2]; // 计算灰度值(使用ITU-R BT.601标准公式,比简单平均更准确) int gray = (int)(0.299 * red + 0.587 * green + 0.114 * blue); // 赋值回蓝、绿、红通道,保留透明度通道不变 originalPixels[i] = (byte)gray; originalPixels[i + 1] = (byte)gray; originalPixels[i + 2] = (byte)gray; // 透明度通道originalPixels[i+3]保持不变 } // 创建WriteableBitmap,直接使用处理后的像素数据 WriteableBitmap bwImage = new WriteableBitmap( _originalImage.PixelWidth, _originalImage.PixelHeight, _originalImage.DpiX, _originalImage.DpiY, PixelFormats.Bgra32, null); bwImage.WritePixels( new Int32Rect(0, 0, _originalImage.PixelWidth, _originalImage.PixelHeight), originalPixels, _originalImage.PixelWidth * 4, 0); return Task.FromResult(bwImage); }
额外说明
- 使用
WriteableBitmap是WPF中处理原始像素数据的正确方式,它不需要编码成图像格式,直接渲染像素数组。 - 灰度计算改用ITU-R BT.601标准公式,比简单平均更符合人眼对色彩的感知,灰度效果更自然。
- 保留了原图像的透明度通道,避免图像出现透明异常。
内容的提问来源于stack exchange,提问作者Лев Поваляев
相关产品推荐
相关产品推荐

