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

24bpp自定义Lockbits图像类仅宽度为4倍数时正常的bug排查求助

问题原因

你遇到的问题本质是Windows GDI+位图的行步长(Stride)对齐规则导致的:

  • 24bppRgb格式的位图默认要求每一行的字节数必须对齐到4的倍数,不足的部分会在每行末尾填充1~3个无意义的占位字节
  • 你当前的代码完全忽略了这个对齐规则,直接按宽度*3计算每行的字节长度,只有当宽度*3刚好是4的倍数时,计算结果才和实际的行长度一致,这就是为什么只有宽度为4倍数时显示正常
  • 当宽度不是4倍数时,每行实际长度比你计算的多了几个填充字节,每读取/写入一行你都会偏移几个字节的位置,越往下偏移量累计越大,就出现了底部内容右移、色彩失真的问题
修改方案

你需要调整三处核心逻辑:

  1. 锁定位图时读取BitmapData.Stride属性获取实际每行字节数,不要硬编码计算
  2. 像素数组长度按Stride * 高度计算,不要使用像素总数*3
  3. 像素索引计算规则改为 y * Stride + x * 3,替换原有的(y*宽度 +x)*3
修正后核心代码

Lock方法修改

private void Lock()
{
    if (!locked)
    {
        Rectangle rect = new Rectangle(0, 0, Width, Height);
        bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        // 用实际步长计算总字节数,Abs兼容自下而上存储的位图
        int totalBytes = Math.Abs(bitmapData.Stride) * Height;
        pixels = new byte[totalBytes];
        Iptr = bitmapData.Scan0;
        Marshal.Copy(Iptr, pixels, 0, pixels.Length);
        locked = true;
    }
}

GetPixel方法修改

public Color GetPixel(int x, int y)
{
    if (!locked) Lock();
    // 使用Stride计算像素起始索引
    int i = y * bitmapData.Stride + x * 3;
    if (i + 2 > pixels.Length || i < 0) throw new IndexOutOfRangeException();
    byte b = pixels[i];
    byte g = pixels[i + 1];
    byte r = pixels[i + 2];
    return Color.FromArgb(r, g, b);
}

SetPixel方法修改

public void SetPixel(int x, int y, Color color)
{
    if (!locked) Lock();
    // 使用Stride计算像素起始索引
    int i = y * bitmapData.Stride + x * 3;
    if (i + 2 < pixels.Length && i >= 0)
    {
        pixels[i] = color.B;
        pixels[i + 1] = color.G;
        pixels[i + 2] = color.R;
    }
}

Unlock方法不需要修改,其余逻辑保持原样即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:24:03