将 BMP 图像转换为 GRF 格式 C# / VB.NET (在 ZPL 打印机中使用)

Convert BMP image to GRF format C# / VB.NET (To use in ZPL printer)

我正在使用以下代码将 BMP 图像转换为 GRF 格式。

Public Shared Function CreateGrf(filename As String, imagename As String) As String
    Dim bmp As Bitmap = Nothing
    Dim imgData As BitmapData = Nothing
    Dim pixels As Byte()
    Dim x As Integer, y As Integer, width As Integer
    Dim sb As StringBuilder
    Dim ptr As IntPtr

    Try
        bmp = New Bitmap(filename)
        imgData = bmp.LockBits(New System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat)
        width = (bmp.Width + 7) \ 8
        pixels = New Byte(width - 1) {}
        sb = New StringBuilder(width * bmp.Height * 2)
        sb.Append(Environment.NewLine)
        ptr = imgData.Scan0

        For y = 0 To bmp.Height - 1
            Marshal.Copy(ptr, pixels, 0, width)
            For x = 0 To width - 1
                sb.AppendFormat("{0:X2}", CByte(Not pixels(x)))
            Next
            sb.Append(Environment.NewLine)
            ptr = ptr.ToInt64() + imgData.Stride
        Next
    Finally
        If bmp IsNot Nothing Then
            If imgData IsNot Nothing Then
                bmp.UnlockBits(imgData)
            End If
            bmp.Dispose()
        End If
    End Try
    Return [String].Format("~DG{0},{1},{2},", imagename, width * y, width) + sb.ToString()
End Function

然而,在转换后的 GRF 文件末尾绘制了一条额外的垂直线,即使 BMP 文件中没有这样的线。除此之外,大小和一切都还可以。 GRF 文件中每行的最后一个像素(十六进制值)似乎不正确。

原始 BMP 文件。

转换后的 GRF 文件

Marshal.Copy(ptr, pixels, 0, width)

位图未按字节对齐。因此,在这种情况下,当您复制其中的数据时,会将剩余的位填充为黑色。

位图为 154 字节宽,创建 19 个完整字节和 2 个剩余像素。所以剩下的6个像素是黑色的。

最后你需要使用宽度可以被八整除的位图,或者确保从位图到 pixels(x) 的数据复制结束占剩余字节。

Public Function ConvertBmp2Grf(fileName As String, imageName As String) As Boolean
    Dim TI As String
    Dim i As Short
    Dim WID As Object
    Dim high As Object
    Dim TEM As Short, BMPL As Short, EFG As Short, n2 As String, LON As String
    Dim header_name As String, a As String, j As Short, COUN As Short, BASE1 As Short

    Dim L As String, TOT As String
    Dim N As Object
    Dim TOT1 As Integer
    Dim LL As Byte

    FileOpen(1, fileName, OpenMode.Binary, , , 1)  ' OPEN BMP FILE TO READ
    FileGet(1, LL, 1)
    TI = Convert.ToString(Chr(LL))
    FileGet(1, LL, 2)
    TI += Convert.ToString(Chr(LL))

    If TI <> "BM" Then
        FileClose()
        Return False
    End If

    i = 17
    FileGet(1, LL, i + 1)
    N = LL * 256
    FileGet(1, LL, i)
    N = (N + LL) * 256

    FileGet(1, LL, i + 3)
    N = (N + LL) * 256
    FileGet(1, LL, i + 2)
    N += LL
    WID = N
    i = 21
    FileGet(1, LL, i + 1)
    N = LL * 256
    FileGet(1, LL, i)
    N = (N + LL) * 256
    FileGet(1, LL, i + 3)
    N = (N + LL) * 256
    FileGet(1, LL, i + 2)
    N += LL
    high = N
    FileGet(1, LL, 27)
    N = LL
    FileGet(1, LL, 29)

    If N <> 1 Or LL <> 1 Then
        'BMP has too many colors, only support monochrome images
        FileClose(1)
        Return False
    End If

    TEM = Int(WID / 8)
    If (WID Mod 8) <> 0 Then
        TEM += 1
    End If
    BMPL = TEM

    If (BMPL Mod 4) <> 0 Then
        BMPL += (4 - (BMPL Mod 4))
        EFG = 1
    End If

    n2 = fileName.Substring(0, fileName.LastIndexOf("\", StringComparison.Ordinal) + 1) + imageName + ".GRF"

    FileOpen(2, n2, OpenMode.Output) 'OPEN GRF TO OUTPUT
    TOT1 = TEM * high : TOT = Mid(Str(TOT1), 2)
    If Len(TOT) < 5 Then
        TOT = Strings.Left("00000", 5 - Len(TOT)) + TOT
    End If

    LON = Mid(Str(TEM), 2)

    If Len(LON) < 3 Then
        LON = Strings.Left("000", 3 - Len(LON)) + LON
    End If

    header_name = imageName
    PrintLine(2, "~DG" & header_name & "," & TOT & "," & LON & ",")

    For i = high To 1 Step -1
        a = ""
        For j = 1 To TEM
            COUN = 62 + (i - 1) * BMPL + j
            FileGet(1, LL, COUN)
            L = LL

            If j = TEM And (EFG = 1 Or (WID Mod 8) <> 0) Then
                BASE1 = 2 ^ ((TEM * 8 - WID) Mod 8)
                L = Int(L / BASE1) * BASE1 + BASE1 - 1
            End If
            L = Not L
            a += Right(Hex(L), 2)
        Next j
        PrintLine(2, a)
    Next i
    FileClose()

    Return True

End Function

1) 删除这部分的“7”:width = (bmp.Width + 7) \ 8

2) 检测位图在Mod之后的剩余值是否为

        if(bmp.Width % 8 > 0)
        {
            var remaining = bmp.Width % 8;
            var newbmp = ResizeImage(bmp, bmp.Width + remaining, bmp.Height);
            bmp.Dispose();
            bmp = newbmp;

        }

ResizeImage 的逻辑

 public static Bitmap ResizeImage(Image image, int width, int height)
{
    var destRect = new Rectangle(0, 0, width, height);
    var oldRect = new Rectangle(0, 0, image.Width, image.Height);
    var destImage = new Bitmap(width, height);

    destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

    using (var graphics = Graphics.FromImage(destImage))
    {
        graphics.FillRectangle(Brushes.White, destRect);
        graphics.CompositingMode = CompositingMode.SourceCopy;
        graphics.CompositingQuality = CompositingQuality.HighQuality;
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.SmoothingMode = SmoothingMode.HighQuality;
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

        using (var wrapMode = new ImageAttributes())
        {
            wrapMode.SetWrapMode(WrapMode.TileFlipXY);
            graphics.DrawImage(image, oldRect, 0, 0, image.Width, image.Height, 
GraphicsUnit.Pixel, wrapMode);
        }
    }

    return destImage;
}