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

CentOS下Mono环境中Bitmap显示异常问题求助

问题:CentOS下Mono运行ASPX图像处理页面,每次显示结果不同

我在CentOS系统中安装Mono并启动xsp4后,运行以下ASPX页面时遇到了奇怪的问题:页面能正常显示图像,但Windows下Mono的显示结果完全正确,CentOS下每次访问图像显示都不一样,实在搞不清原因,恳请懂行的朋友帮忙分析解答!

运行的ASPX代码

<%@ Page Language="C#" %> 
<%@ Import Namespace="System.Drawing" %> 
<%@ Import Namespace="System.Runtime.InteropServices" %> 
<script runat="server">
Bitmap bmp = null;
protected void Page_Load(Object source, EventArgs e) {
    System.Drawing.Image img = System.Drawing.Image.FromFile(@"./test.png");
    bmp = new Bitmap(img);
    bmp = Bin(bmp);
    Response.ContentType = "image/png";
    Response.Flush();
    bmp.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Png);
    Response.End();
}
public static Bitmap Bin(Bitmap src) {
    Bitmap dest = new Bitmap( src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
    System.Drawing.Imaging.BitmapData srcBitmapData = src.LockBits(
        new Rectangle(0, 0, src.Width, src.Height),
        System.Drawing.Imaging.ImageLockMode.WriteOnly,
        src.PixelFormat);
    System.Drawing.Imaging.BitmapData destBitmapData = dest.LockBits(
        new Rectangle(0, 0, dest.Width, dest.Height),
        System.Drawing.Imaging.ImageLockMode.WriteOnly,
        dest.PixelFormat);
    byte[] srcPixels = new byte[srcBitmapData.Stride * src.Height];
    Marshal.Copy(srcBitmapData.Scan0, srcPixels, 0, srcPixels.Length);
    byte[] destPixels = new byte[destBitmapData.Stride * destBitmapData.Height];
    for (int y = 0; y < destBitmapData.Height; y++) {
        for (int x = 0; x < destBitmapData.Width; x++) {
            if (128 <= ConvertToGrayscale(srcPixels, x, y, srcBitmapData.Stride)) {
                int pos = (x >> 3) + destBitmapData.Stride * y;
                destPixels[pos] |= (byte)(0x80 >> (x & 0x7));
            }
        }
    }
    Marshal.Copy(destPixels, 0, destBitmapData.Scan0, destPixels.Length);
    src.UnlockBits(srcBitmapData);
    dest.UnlockBits(destBitmapData);
    return dest;
}
const int RedFactor = (int)(0.298912 * 1024);
const int GreenFactor = (int)(0.586611 * 1024);
const int BlueFactor = (int)(0.114478 * 1024);
private static float ConvertToGrayscale(byte[] srcPixels, int x, int y, int stride) {
    int position = x * 3 + stride * y;
    byte b = srcPixels[position + 0];
    byte g = srcPixels[position + 1];
    byte r = srcPixels[position + 2];
    return (r * RedFactor + g * GreenFactor + b * BlueFactor) >> 10;
}
</script>

不同系统的显示效果

CentOS7显示效果

CentOS7下图像显示效果

Windows10显示效果

Windows10下图像显示效果


问题分析与解决建议

我仔细看了代码,发现最核心的问题应该是这个:

  • LockBits模式使用完全错误:你在读取源图像的像素数据时,给src.LockBits传了ImageLockMode.WriteOnly——这完全搞反了需求啊!我们是要读取源图像的像素,应该用ImageLockMode.ReadOnly才对!
    Windows下的Mono可能对这个错误有一定兼容性,或者内存区域刚好残留了可用数据,所以显示正常;但CentOS下,WriteOnly模式的内存区域是未初始化的随机值,每次访问都会读取到不同的垃圾数据,最终生成的图像自然每次都不一样。

另外还有个潜在隐患需要注意:

  • 像素格式硬编码假设:代码里计算像素位置时用了x*3,默认源图像是24位RGB格式,但如果test.png实际是带Alpha通道的32位格式,或者其他像素格式,这个计算就会出错。不同系统上Mono解析PNG的默认格式可能存在差异,建议先确认源图像的格式,或者添加格式判断逻辑来适配不同情况。

优先解决建议:把src.LockBits中的ImageLockMode.WriteOnly改成ImageLockMode.ReadOnly,这应该能直接解决CentOS下图像显示随机的问题!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:07:51