在打印单色位图图像时,还会打印一条额外的垂直线

本文关键字:打印 一条 垂直线 位图 单色 图像 | 更新日期: 2023-09-27 18:28:32

我正在热敏打印机上打印单色位图图像,在那里我可以打印图像,但在最右边,打印一条垂直线。(该线从右上到右下,厚度接近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个掩码。掩码的实际值取决于打印机的工作方式:您可能需要将额外的位设置为01,并且额外的位可以是最高有效位或最低有效位。上面使用的掩码值假设最高有效位呈现在右侧,并且掩码位应设置为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;
}
MiMo和MyItchyChin的评论帮助我解决了很多问题。

问题是在末尾多出一行。所以从技术上讲,在打印每一行图像时,最后几个字节的信息是不正确的。

出现这个问题的原因是,图像大小可以是任何大小,但当它发送到打印机时,字节宽度应该可以被八整除。在我的情况下,我的打印机需要字节宽度作为输入,所以我必须小心传递图像。

假设我的图像大小为168x168。

byteWidth = Math.Ceiling(bitmapDataWidth / 8.0);

所以这里的byteWidth是21,按照打印机的预期,我对24进行了左移运算,它可以除以8,所以实际上我将图像的大小增加了3个字节,然后开始读取字节信息。我说的这一行是额外的3个字节。由于没有数据,所以黑线正在打印。

我用这种方式编写逻辑,字节数组不影响移位操作,因此它对我有效

早期我在图像处理方面,所以请忽略,如果我犯了一个愚蠢的错误,并在这里解释解决方案。