将 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;
}
我正在使用以下代码将 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;
}