You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win7下用C#生成Gray8位图出现异常结果的问题求助

Win7下WPF生成Gray8格式BMP像素值异常的原因与解决方法

问题原因

Win7系统自带的WindowsCodecs.dll中的BMP编码器存在兼容性bug:当处理PixelFormats.Gray8(8位灰度,256级)格式图像时,会错误地将8位灰度数据量化为4位灰度(仅16级),再把4位值按值 × 17(255/15=17)映射回8位,最终出现你观察到的input / 16 * 17的像素值。Win10版本的编码器已修复该问题,可正确保留8位灰度信息。

解决方案

方案1:转换为RGB24格式后编码

Win7的BMP编码器对RGB格式处理正常,可将Gray8图像转换为24位RGB(R=G=B=灰度值)后再编码,代码修改如下:

var width = 4;
var height = 4;
var rect = new Int32Rect() { Width = width, Height = height };

var bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray8, null);
var data = new byte[width * height];
for (var i = 0; i < data.Length; i++)
{
    data[i] = (byte)(i * 2);
}
bitmap.WritePixels(rect, data, width, 0);

// 将Gray8转换为RGB24格式
var rgbBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Rgb24, null);
var rgbData = new byte[width * height * 3];
for (int i = 0; i < data.Length; i++)
{
    rgbData[i * 3] = data[i];     // B通道
    rgbData[i * 3 + 1] = data[i]; // G通道
    rgbData[i * 3 + 2] = data[i]; // R通道
}
rgbBitmap.WritePixels(rect, rgbData, width * 3, 0);

// 使用RGB24图像编码
var encoder = new BmpEncoder();
encoder.Frames.Add(BitmapFrame.Create(rgbBitmap));
using (var s = new FileStream(filename, FileMode.Create))
{
    encoder.Save(s);
}

方案2:手动构造标准8位灰度BMP文件

绕过WPF的BmpEncoder,直接按照BMP格式规范生成带256级灰度调色板的8位灰度BMP,彻底避免编码器兼容性问题:

var width = 4;
var height = 4;
var data = new byte[width * height];
for (var i = 0; i < data.Length; i++)
{
    data[i] = (byte)(i * 2);
}

using (var fs = new FileStream(filename, FileMode.Create))
using (var bw = new BinaryWriter(fs))
{
    // 写入BMP文件头
    bw.Write((byte)'B');
    bw.Write((byte)'M');
    int rowPad = (4 - (width % 4)) % 4;
    int fileSize = 54 + 256 * 4 + width * height + rowPad * height;
    bw.Write(fileSize);
    bw.Write((ushort)0);
    bw.Write((ushort)0);
    bw.Write(54 + 256 * 4); // 像素数据起始偏移

    // 写入BITMAPINFOHEADER
    bw.Write(40); // 信息头大小
    bw.Write(width);
    bw.Write(height);
    bw.Write((ushort)1); // 平面数
    bw.Write((ushort)8); // 位深度
    bw.Write((uint)0); // 无压缩
    bw.Write((uint)(width * height + rowPad * height)); // 像素数据总大小
    bw.Write(96); // 水平DPI
    bw.Write(96); // 垂直DPI
    bw.Write((uint)256); // 调色板颜色数
    bw.Write((uint)256); // 重要颜色数

    // 写入256级灰度调色板(R=G=B=i,Alpha=0)
    for (int i = 0; i < 256; i++)
    {
        bw.Write((byte)i); // B
        bw.Write((byte)i); // G
        bw.Write((byte)i); // R
        bw.Write((byte)0); // Alpha
    }

    // 写入像素数据(BMP行存储顺序为从下到上,每行需对齐到4字节)
    for (int y = height - 1; y >= 0; y--)
    {
        int rowStart = y * width;
        bw.Write(data, rowStart, width);
        // 补位到4字节边界
        if (rowPad > 0)
        {
            bw.Write(new byte[rowPad]);
        }
    }
}

注意:原代码中encoder.Frames.Add(BitmapFrame.Create(bitmap);存在语法错误,需修正为encoder.Frames.Add(BitmapFrame.Create(bitmap));

内容的提问来源于stack exchange,提问作者mingpepe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 20:50:29