1

我正在热敏打印机上打印单色位图图像,我可以在其中打印图像,但在最右边,正在打印一条垂直线。(线从右上到右下,粗近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;

在这里,我将单色位图图像转换为字节数组,并从字节数组转换为十六进制字符串。我在论坛上搜索过,但没有讨论这种错误。(可能是我犯了愚蠢的错误)任何人都可以建议我到底在哪里犯了错误。

提前致谢。

干杯,西瓦。

4

3 回答 3

0

For performance reasons each horizontal row in a Bitmap is buffered to a DWORD boundary (see this answer for more details). So if your Bitmap's width multiplied by it's bits-per-pixel(bpp) is not divisible by 32 (DWORD = 32bits) then it's padded with extra bits. So a 238x40 1bpp Bitmap has a memory foot print of 8 DWORDs per row or 256 bits.

The BitmapData object's Stride property is the number of bytes that each row of your bitmap consumes in memory. When you capture the Byte Array, you're capturing that padding as well.

Before you convert the byte array to hex you need to trim the buffer off the end. The following function should do that nicely.

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;
}
于 2013-08-21T17:08:59.443 回答
0

MiMo 和 MyItchyChin 的评论帮助我解决了这个问题。

问题是在最后得到额外的线。所以从技术上讲,在打印每一行图像时,最后几个字节的信息是不正确的。

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

假设我有图像 168x168 大小。

byteWidth = Math.Ceiling(bitmapDataWidth / 8.0);

所以这里的 byteWidth 是 21,根据打印机的预期,我做了左移操作到 24,可以被 8 整除,所以实际上我将图像的大小增加了 3 个字节,然后开始读取字节信息。我正在谈论的那一行是额外的 3 个字节。由于那里没有数据,因此正在打印黑线。

我以这种方式编写了逻辑,其中字节数组不会影响移位操作,因此它对我有用。

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

于 2013-08-23T14:26:40.757 回答
0

您正在返回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;
}

它创建了一个具有正确大小的actualBitmapFileData数组。bitmapFileData

请注意,每行的最后一个字节将仅包含nBits像素 - 因此需要“屏蔽”以清除与任何像素不对应的额外位。这是由 完成的& masks[nBits],其中masks是一个包含 8 个掩码的 8 字节数组。掩码的实际值取决于打印机的工作方式:您可能需要将额外的位设置为01,而额外的位可以是最重要的或最不重要的。上面使用的掩码值假定最高有效位呈现在右侧,并且掩码位应设置为 0。根据打印机的工作方式,可能需要交换位和/或将掩码位设置为1 而不是零(补充掩码并使用|而不是&

于 2013-08-21T14:18:41.660 回答