使用 LockBits 直接操作像素數據進行灰度轉換,結果圖像出現條紋、錯位、顏色錯亂。
BitmapData.Stride(跨度/行寬)不等於 Width * BytesPerPixel。Windows 為了內存對齊,要求每行數據大小為 4 字節倍數。例如:
代碼中按 Width * Height * 3 分配緩衝區並連續讀寫,忽略了行尾填充字節,導致後續行數據偏移。
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
int stride = bmpData.Stride; // 必須使用實際 Stride
IntPtr ptr = bmpData.Scan0;
int bytes = stride * bmp.Height; // 總字節數含填充
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
for (int y = 0; y < bmp.Height; y++) {
int rowOffset = y * stride;
for (int x = 0; x < bmp.Width; x++) {
int idx = rowOffset + x * 3; // 24bpp: BGR 順序
byte b = rgbValues[idx];
byte g = rgbValues[idx + 1];
byte r = rgbValues[idx + 2];
byte gray = (byte)(r * 0.299 + g * 0.587 + b * 0.114);
rgbValues[idx] = rgbValues[idx + 1] = rgbValues[idx + 2] = gray;
}
}
Marshal.Copy(rgbValues, 0, ptr, bytes);
bmp.UnlockBits(bmpData);
bmpData.Stride 而非自行計算行寬。PixelFormat.Format24bppRgb 為 BGR 順序;32bpp 含 Alpha 通道。Gray = R*0.299 + G*0.587 + B*0.114(BT.601 標準)。