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

4.7k views Asked by At

I am using following code to convert BMP Image to GRF format.

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

However there is an extra vertical line drawn at the end of the converted GRF file even though there is no such line in the BMP file. Other than that the size and everything is Ok. It seems the last pixel (hex value) of each row is not correct in the GRF file.

Original BMP Image

Original BMP File.

Converted GRF FIle

Converted GRF FIle

3

There are 3 answers

1
Sugath On BEST ANSWER
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
0
banno On

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

The Bitmap is not byte aligned. So in this case when you copy the data in it is filling in the left over bits as black.

the bitmap is 154 bytes wide which creates 19 full bytes and 2 left over pixels. So the remaining 6 pixels are black.

In the end you need to use bitmaps with widths that are divisible by eight or make sure the end of the data copy from the bitmap to pixels(x) accounts for the remaining bytes.

0
Nick Chan Abdullah On

1) remove "7" in this part : width = (bmp.Width + 7) \ 8

2) detect if the bitmap's remaining value after Mod

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

        }

the logic for 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;
}