user2256857
user2256857

Reputation: 179

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

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

Upvotes: 3

Views: 5144

Answers (4)

Mauro Lodi
Mauro Lodi

Reputation: 1

This is my go at rewriting the code using .NET version 8.0. I hope this might be helpful.

As input, a monochrome BMP file is used, and the output is a GRF file.

using System.Drawing;
using System.Text;

if (args.Length < 2)
{
  Console.WriteLine("Usage: Bmp2Grf <BMP file> <GRF file>");
  return;
}

var fileName = args[0];
var outFile = args[1];

int TEM;
int TotBytes;
int nibble;
StringBuilder grf = new();

//open a bitmap file to read
Bitmap bitmap = (Bitmap)Image.FromFile(fileName);

Console.WriteLine("Width: " + bitmap.Width);
Console.WriteLine("Height: " + bitmap.Height);
Console.WriteLine("PixelFormat: " + bitmap.PixelFormat);

if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format1bppIndexed)
{
  Console.WriteLine("BMP has too many colors, only support monochrome images");
  return;
}

TEM = bitmap.Width / 8;
//width must be divisible by 8
if ((bitmap.Width % 8) != 0)
  TEM += 1;

TotBytes = TEM * bitmap.Height;

grf.Append("~DGR:" + Path.GetFileName(outFile) + "," + TotBytes.ToString("00000") + "," + TEM.ToString("000") + ",");

for (int y = 0; y < bitmap.Height; y++)
{
  for (int x = 0; x < bitmap.Width; x += 4)
  {
    //every 4 pixels we have a nibble
    nibble = 0;

    for (int i = 0; i < 4; i++)
    {
      if (x + i >= bitmap.Width)
        continue;

      if (bitmap.GetPixel(x + i, y).R == 0)
        nibble += 1 << (3-i);
    }

    grf.Append(nibble.ToString("X1"));
  }
  grf.AppendLine();
}

//save the GRF file
File.WriteAllText(outFile, grf.ToString());

Upvotes: 0

Nick Chan Abdullah
Nick Chan Abdullah

Reputation: 375

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;
}

Upvotes: 0

Sugath
Sugath

Reputation: 293

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

Upvotes: 2

banno
banno

Reputation: 1544

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.

Upvotes: 2

Related Questions