我正在热敏打印机上打印单色位图图像,在那里我可以打印图像,但在最右边,打印一条垂直线。(该线从右上到右下,厚度接近2mm)
Bitmap image = new Bitmap(imagePath, false);
int imageDepth = System.Drawing.Bitmap.GetPixelFormatSize(image.PixelFormat);
Rectangle monoChromeBitmapRectangle = new Rectangle(0, 0, image.Width, image.Height);
BitmapData monoChromebmpData = null;
int stride = 0;
monoChromebmpData = image.LockBits(monoChromeBitmapRectangle, ImageLockMode.ReadOnly, resizedImage.PixelFormat);
IntPtr ptr = monoChromebmpData.Scan0;
stride = monoChromebmpData.Stride;
int numbytes = stride * image.Height;
byte[] bitmapFileData = new byte[numbytes];
Marshal.Copy(ptr, bitmapFileData, 0, numbytes);
image.UnlockBits(monoChromebmpData);
//Invert bitmap colors
for (int i = 0; i < bitmapFileData.Length; i++)
{
bitmapFileData[i] ^= 0xFF;
}
StringBuilder hexaDecimalImageDataString = new StringBuilder(bitmapFileData.Length * 2);
foreach (byte b in bitmapFileData)
hexaDecimalImageDataString.AppendFormat("{0:X2}", b);
return hexaDecimalImageDataString;
在这里,我将单色位图图像转换为字节数组,并从字节数组转换为十六进制字符串。我在论坛上搜索了一下,但没有讨论这种错误。(可能是我犯了一个愚蠢的错误)谁能说出我到底在哪里犯了错吗。
提前谢谢。
干杯,西瓦。
您返回的是monoChromebmpData.Stride * image.Height
字节,即图像中的每一行都将恰好是monoChromebmpData.Stride * 8
像素宽,但原始图像的像素宽度可能小于此宽度,因此右侧会有额外的垂直线。
试试这样的东西:
byte[] masks = new byte[]{0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
int byteWidth = (image.Width+7)/8;
int nBits = imageWidth % 8;
byte[] actualBitmapFileData = new byte[byteWidth*image.Height];
int yFrom = 0;
for (int y=0; y<image.Height; y++) {
for (int x=0; x<byteWidth-1; x++) {
actualBitmapFileData[y*byteWidth + x] = (bitmapFileData[yFrom + x] ^ 0xFF);
}
int lastX = byteWidth - 1;
actualBitmapFileData[y*byteWidth + lastX] = (bitmapFileData[yFrom + lastX] ^ 0xFF) & masks[nBits];
yFrom += stride;
}
它为CCD_ 4创建具有正确大小的CCD_。
请注意,每行的最后一个字节将只包含nBits
像素,因此需要"屏蔽"以清除与任何像素不对应的额外位。这是由& masks[nBits]
完成的,其中masks
是一个由8个字节组成的数组,其中要使用8个掩码。掩码的实际值取决于打印机的工作方式:您可能需要将额外的位设置为0
或1
,并且额外的位可以是最高有效位或最低有效位。上面使用的掩码值假设最高有效位呈现在右侧,并且掩码位应设置为0。根据打印机的工作方式,可能需要交换位和/或将屏蔽位设置为1而不是零(补充屏蔽并使用|
而不是&
)
出于性能原因,位图中的每个水平行都缓冲到DWORD边界(有关更多详细信息,请参阅此答案)。因此,如果位图的宽度乘以它的每像素比特数(bpp)不能被32整除(DWORD=32比特),那么它会被额外的比特填充。因此,238x40 1ppp位图的内存足迹为每行8 DWORD或256位。
BitmapData对象的Stride属性是位图的每一行在内存中消耗的字节数。当您捕获字节数组时,您也在捕获填充。
在将字节数组转换为十六进制之前,需要修剪末尾的缓冲区。下面的函数应该可以很好地做到这一点。
public static byte[] TruncatePadding(byte[] PaddedImage, int Width, int Stride, int BitsPerPixel)
{
//Stride values can be negative
Stride = Math.Abs(Stride);
//Get the actual number of bytes each row contains.
int shortStride = (int)Math.Ceiling((double)(Width*BitsPerPixel/8));
//Figure out the height of the image from the array data
int height = PaddedImage.Length / Stride;
if (height < 1)
return null;
//Allocate the new array based on the image width
byte[] truncatedImage = new byte[shortStride * height];
//Copy the data minus the padding to a new array
for(int i = 0; i < height; i++)
Buffer.BlockCopy(PaddedImage,i*Stride,truncatedImage,i*shortStride,shortStride);
return truncatedImage;
}
问题是在末尾多出一行。所以从技术上讲,在打印每一行图像时,最后几个字节的信息是不正确的。
出现这个问题的原因是,图像大小可以是任何大小,但当它发送到打印机时,字节宽度应该可以被八整除。在我的情况下,我的打印机需要字节宽度作为输入,所以我必须小心传递图像。
假设我的图像大小为168x168。
byteWidth = Math.Ceiling(bitmapDataWidth / 8.0);
所以这里的byteWidth是21,按照打印机的预期,我对24进行了左移运算,它可以除以8,所以实际上我将图像的大小增加了3个字节,然后开始读取字节信息。我说的这一行是额外的3个字节。由于没有数据,所以黑线正在打印。
我用这种方式编写逻辑,字节数组不影响移位操作,因此它对我有效
早期我在图像处理方面,所以请忽略,如果我犯了一个愚蠢的错误,并在这里解释解决方案。