从.NET 4.8迁移至.NET 8:1bpp Bitmap转ImageSharp的实现疑问
解决ImageSharp生成符合1bpp Bitmap Stride要求的字节数组问题
核心问题原因
原.NET System.Drawing.Bitmap 的1bpp格式Stride遵循4字节对齐规则,即每行字节数向上取整到4的倍数;而ImageSharp的Image<L8>直接输出的像素数据是连续无填充的,两者结构差异导致Zebra打印异常。
解决方案步骤
1. 计算与原Bitmap一致的Stride
先计算1bpp每行所需的最小字节数,再对齐到4字节边界:
private static int CalculateBitmapStride(int width) { // 1bpp每行有效字节数:向上取整(宽度/8) int bytesPerRow = (width + 7) / 8; // 对齐到4字节边界,匹配System.Drawing.Bitmap的Stride规则 return ((bytesPerRow + 3) / 4) * 4; }
2. 转换Image为符合要求的字节数组
遍历每行像素,将L8格式转换为1bpp位数据,再添加0xFF填充字节到Stride长度:
using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; public static byte[] ConvertL8ToBitmap1BppBytes(Image<L8> image) { int width = image.Width; int height = image.Height; int stride = CalculateBitmapStride(width); int effectiveBytesPerRow = (width + 7) / 8; byte[] outputBuffer = new byte[stride * height]; for (int y = 0; y < height; y++) { int rowStart = y * stride; Span<L8> rowPixels = image.GetPixelRowSpan(y); byte[] rowData = new byte[effectiveBytesPerRow]; // 将L8像素转换为1bpp位数据(匹配原Bitmap位顺序:字节最高位对应行最左侧像素) for (int x = 0; x < width; x++) { int byteIdx = x / 8; int bitIdx = 7 - (x % 8); // 从最高位开始填充 bool isWhitePixel = rowPixels[x].PackedValue == 255; if (isWhitePixel) { rowData[byteIdx] |= (byte)(1 << bitIdx); } else { rowData[byteIdx] &= (byte)~(1 << bitIdx); } } // 复制有效数据到输出数组 rowData.CopyTo(outputBuffer, rowStart); // 填充行尾对齐字节为0xFF(与原代码逻辑一致) for (int i = rowStart + effectiveBytesPerRow; i < rowStart + stride; i++) { outputBuffer[i] = 0xFF; } } return outputBuffer; }
关键注意事项
- 位顺序匹配:原Bitmap的1bpp格式中,每个字节的最高位对应行最左侧像素,转换时需按此规则填充位数据,否则会出现图像反转或错位。
- 像素值映射:如果原Bitmap的1bpp定义与示例相反(如0代表白,1代表黑),需调整
isWhitePixel的判断逻辑。 - 行顺序一致性:ImageSharp的
GetPixelRowSpan返回的是从上到下的行数据,与原BitmapData默认的TopDown顺序一致,无需额外反转。
内容的提问来源于stack exchange,提问作者Luis Abreu
相关产品推荐
相关产品推荐

