Вот как я справлялся с этим в прошлом. Этот код был извлечен из дизайнера меток перетаскивания, поэтому в нем есть некоторые преобразования для обработки различий в DPI, которые вам придется удалить, если не нужно. Но основной процесс состоял в том, чтобы получить растровое изображение, изменить его размер таким образом, чтобы его ширина делилась на 8 для кодирования, сделать его монохромным, поскольку это был пиксельный термопринтер вкл / выкл, преобразовать его биты в шестнадцатеричную строку и затем использовать карту сжатия ZPLчтобы сжать его (чем меньше мы получим смехотворно длинную строку, которую нужно отправить навсегда на принтер).
Порог 0,8 - это просто число, которое, как мне показалось, работает достаточно надежно, это предельное значениедля принятия решения о том, включен ли бит в зависимости от того, насколько он темный, вам может потребоваться настроить его в соответствии с вашими потребностями.
Входное изображение было:
Вывод с помощью онлайн-просмотра Labelary ZPL (http://labelary.com/viewer.html):
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim imgZpl As String = TiffToZpl("C:\Users\sooho\Desktop\so.tif", 0.8)
Debug.Print(imgZpl)
End Sub
Public Function TiffToZpl(tiffFilePath As String, grayscaleThreshold As Single) As String
Dim ms As New System.IO.MemoryStream
System.Drawing.Bitmap.FromFile(tiffFilePath).Save(ms, System.Drawing.Imaging.ImageFormat.Png)
Dim bmp = New System.Drawing.Bitmap(ms)
ResizeBitmapMod8(bmp)
bmp = Monochrome(bmp, grayscaleThreshold)
Return BitmapToZpl(bmp, 0, 0)
End Function
Private Function BitmapToZpl(ByRef bm As Bitmap, top As Integer, left As Integer) As String
Dim ret As New System.Text.StringBuilder
Dim lastHexChar As Nullable(Of Char) = Nothing
Dim hexCharCount As Integer = 0
Dim finalHex As New System.Text.StringBuilder
Dim bitCount As Integer = 0
Dim binaryCount As Integer = 0
For r As Integer = 0 To bm.Height - 1
For c As Integer = 0 To bm.Width - 1
bitCount += 1
If Not bm.GetPixel(c, r).Name.Equals("ffffffff") Then
Select Case bitCount
Case 1 : binaryCount += 8
Case 2 : binaryCount += 4
Case 3 : binaryCount += 2
Case 4 : binaryCount += 1
End Select
End If
If bitCount = 4 Then
If lastHexChar Is Nothing Then
lastHexChar = CChar(hexMap(binaryCount))
hexCharCount = 1
Else
If CChar(hexMap(binaryCount)) = lastHexChar Then
hexCharCount += 1
Else
While hexCharCount > 0
Dim maxKey As Integer = 0
For Each key As Integer In zplHexCompressionMap.Keys
If key <= hexCharCount Then
maxKey = key
Else
Exit For
End If
Next
finalHex.Append(zplHexCompressionMap(maxKey) & lastHexChar)
hexCharCount -= maxKey
End While
lastHexChar = CChar(hexMap(binaryCount))
hexCharCount = 1
End If
End If
bitCount = 0
binaryCount = 0
End If
Next c
Next r
While hexCharCount > 0
Dim maxKey As Integer = 0
For Each key As Integer In zplHexCompressionMap.Keys
If key <= hexCharCount Then
maxKey = key
Else
Exit For
End If
Next
finalHex.Append(zplHexCompressionMap(maxKey) & lastHexChar)
hexCharCount -= maxKey
End While
Dim totalBytes As Integer = CInt((bm.Height * bm.Width) / 8)
Dim byteWidth As Integer = CInt(bm.Width / 8)
Dim adjustedLeft As Integer = CInt(left * dpiMultiplier_ScreenToPrinter)
Dim adjustedTop As Integer = CInt(top * dpiMultiplier_ScreenToPrinter)
ret.Append("^FO" & adjustedLeft.ToString & "," & adjustedTop.ToString)
ret.Append("^GFA," & totalBytes.ToString & "," & totalBytes.ToString & "," & byteWidth.ToString & ",,")
ret.Append(finalHex.ToString)
ret.Append("^FS")
Return ret.ToString
End Function
Private Sub ResizeBitmapMod8(ByRef bm As Bitmap)
'Resizes a bitmap to its nearest width multiple of 8. Images must be hex-encoded
'to be send to the printer, and hex encoding requires pairs of 4 bits, so the
'the image's width must be divisible by 8 or the resulting image will have a black
'strip down the side once it's decoded by the zpl printer
If bm.Width Mod 8 <> 0 Then
Dim width As Integer = bm.Width
Dim height As Integer = bm.Height
Dim aspectRatio As Double = width / height
Dim lowMultiplier As Integer = CInt(Int(width / 8))
Dim highMultiplier As Integer = lowMultiplier + 1
Dim diffBelow As Integer = width - (lowMultiplier * 8)
Dim diffAbove As Integer = (highMultiplier * 8) - width
If diffBelow < diffAbove Then
width = lowMultiplier * 8
Else
width = highMultiplier * 8
End If
height = CInt(width / aspectRatio)
Dim bmResized As New Bitmap(width, height)
Dim gfxResized As Graphics = Graphics.FromImage(bmResized)
gfxResized.DrawImage(bm, 0, 0, bmResized.Width + 1, bmResized.Height + 1)
bm = bmResized
End If
End Sub
Private Function Monochrome(ByVal bmOriginal As Bitmap, grayscaleThreshold As Single) As Bitmap
Dim gsBitmap As New Bitmap(bmOriginal)
Try
'Convert image to grayscale
Dim gfxSource As Graphics = Graphics.FromImage(gsBitmap)
Dim imgAttr As New System.Drawing.Imaging.ImageAttributes
Dim imgRec As Rectangle = New Rectangle(0, 0, gsBitmap.Width, gsBitmap.Height)
imgAttr.SetColorMatrix(New System.Drawing.Imaging.ColorMatrix(grayMatrix))
imgAttr.SetThreshold(grayscaleThreshold)
gfxSource.DrawImage(gsBitmap, imgRec, 0, 0, gsBitmap.Width, gsBitmap.Height, GraphicsUnit.Pixel, imgAttr)
Catch ex As Exception
'image already has an indexed color matrix
End Try
'Convert format to 1-index monochrome
Dim mcBitmap As Bitmap = New Bitmap(gsBitmap.Width, gsBitmap.Height, Imaging.PixelFormat.Format1bppIndexed)
Dim mcBmData As Imaging.BitmapData = mcBitmap.LockBits(
New Rectangle(0, 0, mcBitmap.Width, mcBitmap.Height),
Imaging.ImageLockMode.ReadWrite,
Imaging.PixelFormat.Format1bppIndexed)
For y As Integer = 0 To gsBitmap.Height - 1
For x As Integer = 0 To gsBitmap.Width - 1
Dim pixelColor As Color = gsBitmap.GetPixel(x, y)
If pixelColor.Name = "ffffffff" Then
Dim index As Integer = y * mcBmData.Stride + (x >> 3)
Dim p As Byte = Runtime.InteropServices.Marshal.ReadByte(mcBmData.Scan0, index)
Dim mask As Byte = CByte(&H80 >> (x And &H7))
p = p Or mask
Runtime.InteropServices.Marshal.WriteByte(mcBmData.Scan0, index, p)
End If
Next x
Next y
mcBitmap.UnlockBits(mcBmData)
Return mcBitmap
End Function
Public Const DPI_Screen As Double = 96
Public Const DPI_Printer As Double = 203
Public Const dpiMultiplier_ScreenToPrinter As Double = DPI_Printer / DPI_Screen
Public grayMatrix()() As Single = {
New Single() {0.299F, 0.299F, 0.299F, 0, 0},
New Single() {0.587F, 0.587F, 0.587F, 0, 0},
New Single() {0.114F, 0.114F, 0.114F, 0, 0},
New Single() {0, 0, 0, 1, 0},
New Single() {0, 0, 0, 0, 1}}
Private hexMap() As String = {
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F"}
Private zplHexCompressionMap As New SortedDictionary(Of Integer, Char) From {
{1, "G"c}, {2, "H"c}, {3, "I"c}, {4, "J"c}, {5, "K"c},
{6, "L"c}, {7, "M"c}, {8, "N"c}, {9, "O"c}, {10, "P"c},
{11, "Q"c}, {12, "R"c}, {13, "S"c}, {14, "T"c}, {15, "U"c},
{16, "V"c}, {17, "W"c}, {18, "X"c}, {19, "Y"c}, {20, "g"c},
{40, "h"c}, {60, "i"c}, {80, "j"c}, {100, "k"c}, {120, "l"c},
{140, "m"c}, {160, "n"c}, {180, "o"c}, {200, "p"c}, {220, "q"c},
{240, "r"c}, {260, "s"c}, {280, "t"c}, {300, "u"c}, {320, "v"c},
{340, "w"c}, {360, "x"c}, {380, "y"c}, {400, "z"c}}
End Class