Привет!
За год использования были найдены следующие баги и внесены следующие изменения:
1. От пользователей были получены жалобы на плохое чтение штихкодов: коды хорошо читались с относительно большого расстояния, что не всегда удобно. Я нашел причину в том, что Excel (в моем случае - 2007) печатает линии с маленьким промежутком порядка 0,1-0,05 мм, который можно легко увидеть не печати, несмотря на то что код генерирует линии "в стык". Судя по всему, это является препятствием для чтения кодо в малого расстояния - сканер не в состоянии декодировать последовательность.
Данный баг починил тем, что теперь линии печатаются на 10% ближе друг к другу. Это значение было экспериментально подобрано для моего PROTON как наилучшее. Возможно, в вашем случае будет по-другому.
2. Если штрихи рисуются на листе, на котором уже находятся другие графические элементы (кнопки и пр.), цвет и толщина линий почему-то устанавливались некорректно. Посему применен новый метод рисования линий.
3. Начал получать жалобы, что некоторые последовательности штрихов не читаются никакими средствами. Изучая вопрос, нашел большой баг в алгоритме.
Баг заключается в кодировании символов 43-46. В стандарте написано:
Note that the characters ($), (%), (/), and (+) are special characters that are used to encode all 128 ASCII characters using Code 93's Full ASCII mode.
In Code 39, four of the characters ($, %, /, and +) are used to optionally encode all 128 characters-but there is no way to know whether those characters are being used as shift characters in Full ASCII mode or whether they are being used to represent $, %, /, and +. In Code 93 this problem is solved by reserving these four special characters exclusively to "shift" into Full ASCII mode.
Поискав в различных ресурсах на тему ASCII-кодов, так и не нашел какие ASCII-коды соответствуют этим "волшебным" символам. Поэтому ранее использовал те же символы, что и для значений 39-42:
SymbolChar(39) = "$"
SymbolChar(40) = "/"
SymbolChar(41) = "+"
SymbolChar(42) = "%"
SymbolChar(43) = "$"
SymbolChar(44) = "%"
SymbolChar(45) = "/"
SymbolChar(46) = "+"
Это привело к тому, что в контрольные суммы записывались неверные символы и сканер не мог правильно раскодировать штрихкод.
Проблема решилась применением кодирования символов, НЕ ВХОДЯЩИХ в стандарт Code93:
SymbolChar(43) = Chr(60)
SymbolChar(44) = Chr(61)
SymbolChar(45) = Chr(62)
SymbolChar(46) = Chr(63)
В работе алгоритма в конечном счёте эти символы являются всего лишь ссылками на битовые последовательности и не являются "читаемыми" символами и не попадают в раскодированную строку.
4. Подсчёт контрольных сумм С и К приведен в соответствие со стандартом:
The "C" checksum character is the modulo 47 remainder of the sum of the weighted value of the data characters. The weighting value starts at "1" for the right-most data character, 2 for the second to last, 3 for the third-to-last, and so on up to 20. After 20, the sequence wraps around back to 1.
The "K" checksum character is calculated in basically the same way except that the weighting goes from 1 to 15. Also, the right-most character is now the "C" checksum character which was calculated in the step above.
Всё это привело к тому, что код стал работать правильно.
Окончательная версия кода. Красным показаны изменения:
Sub Code93Generate(ByVal X As Single, ByVal Y As Single, ByVal Height As Single, ByVal LineWeight As Single, _
ByRef TargetSheet As Worksheet, ByVal Content As String)
' X in mm (0.376042)
' Y in mm (0.341)
' Height in mm
' LineWeight in pt
Dim SSSymbol As String
Const Tbar_Symbol As String = "1"
Dim CurBar As Integer
Dim SymbolChar(0 To 46) As String
Dim SymbolValue(0 To 46) As Integer
Dim SymbolString(0 To 46) As String * 9
Dim C_WeightSum As Single
Dim C_WeightIndex, K_WeightIndex As Integer 'weight indexes
Dim K_WeightSum As Single
Dim C_CheckSum As Single
Dim K_CheckSum As Single
Dim ContentString As String
Dim i, j, k As Integer
SSSymbol = "101011110"
For i = 0 To 46
SymbolValue(i) = i
Next i
For i = 0 To 9 'digits
SymbolChar(i) = i
Next i
For i = 10 To 35 'digits
SymbolChar(i) = Chr(i + 55)
Next i
SymbolChar(36) = "-"
SymbolChar(37) = "."
SymbolChar(38) = " "
SymbolChar(39) = "$"
SymbolChar(40) = "/"
SymbolChar(41) = "+"
SymbolChar(42) = "%"
SymbolChar(43) = Chr(60)
SymbolChar(44) = Chr(61)
SymbolChar(45) = Chr(62)
SymbolChar(46) = Chr(63)
SymbolString(0) = "100010100"
SymbolString(1) = "101001000"
SymbolString(2) = "101000100"
SymbolString(3) = "101000010"
SymbolString(4) = "100101000"
SymbolString(5) = "100100100"
SymbolString(6) = "100100010"
SymbolString(7) = "101010000"
SymbolString(8 ) = "100010010"
SymbolString(9) = "100001010"
SymbolString(10) = "110101000"
SymbolString(11) = "110100100"
SymbolString(12) = "110100010"
SymbolString(13) = "110010100"
SymbolString(14) = "110010010"
SymbolString(15) = "110001010"
SymbolString(16) = "101101000"
SymbolString(17) = "101100100"
SymbolString(18) = "101100010"
SymbolString(19) = "100110100"
SymbolString(20) = "100011010"
SymbolString(21) = "101011000"
SymbolString(22) = "101001100"
SymbolString(23) = "101000110"
SymbolString(24) = "100101100"
SymbolString(25) = "100010110"
SymbolString(26) = "110110100"
SymbolString(27) = "110110010"
SymbolString(28) = "110101100"
SymbolString(29) = "110100110"
SymbolString(30) = "110010110"
SymbolString(31) = "110011010"
SymbolString(32) = "101101100"
SymbolString(33) = "101100110"
SymbolString(34) = "100110110"
SymbolString(35) = "100111010"
SymbolString(36) = "100101110"
SymbolString(37) = "111010100"
SymbolString(38) = "111010010"
SymbolString(39) = "111001010"
SymbolString(40) = "101101110"
SymbolString(41) = "101110110"
SymbolString(42) = "110101110"
SymbolString(43) = "100100110"
SymbolString(44) = "111011010"
SymbolString(45) = "111010110"
SymbolString(46) = "100110010"
X = X / 0.376042 'mm to pt
Y = Y / 0.341 'mm to pt
Height = Height / 0.341 'mm to pt
Content = UCase(Content)
'C checksum counting
C_WeightIndex = Len(Content) Mod 20
If C_WeightIndex = 0 Then C_WeightIndex = 20
For i = 1 To Len(Content)
j = -1
Do
If j > 46 Then Exit Sub
j = j + 1
Loop While Mid(Content, i, 1) <> SymbolChar(j)
'C_WeightSum = C_WeightSum + SymbolValue(j) * (Len(Content) + 1 - i) ' 20
C_WeightSum = C_WeightSum + SymbolValue(j) * C_WeightIndex
C_WeightIndex = C_WeightIndex - 1
If C_WeightIndex = 0 Then C_WeightIndex = 20
Next i
C_CheckSum = C_WeightSum Mod 47
Content = Content + SymbolChar(C_CheckSum)
'K checksum counting
K_WeightIndex = Len(Content) Mod 15
If K_WeightIndex = 0 Then C_WeightIndex = 15
For i = 1 To Len(Content)
j = -1
Do
j = j + 1
Loop While Mid(Content, i, 1) <> SymbolChar(j)
'K_WeightSum = K_WeightSum + SymbolValue(j) * (Len(Content) + 1 - i) ' 15
K_WeightSum = K_WeightSum + SymbolValue(j) * K_WeightIndex ' 15
K_WeightIndex = K_WeightIndex - 1
If K_WeightIndex = 0 Then K_WeightIndex = 15
Next i
K_CheckSum = K_WeightSum Mod 47
Content = Content + SymbolChar(K_CheckSum)
ContentString = SSSymbol
For i = 1 To Len(Content)
j = -1
Do
j = j + 1
Loop While Mid(Content, i, 1) <> SymbolChar(j)
ContentString = ContentString + SymbolString(j)
Next i
ContentString = ContentString + SSSymbol + Tbar_Symbol
'Barcode drawing
CurBar = 0
For i = 1 To Len(ContentString)
Select Case Mid(ContentString, i, 1)
Case 0
CurBar = CurBar + 1
Case 1
CurBar = CurBar + 1
With TargetSheet.Shapes.AddLine(X + (CurBar * LineWeight) * 0.9, Y, X + (CurBar * LineWeight) * 0.9, (Y + Height)).Line
.Weight = LineWeight
.ForeColor.RGB = vbBlack
End With
End Select
Next i
End Sub
На этом разработку кода планирую завершить, так как CODE93 довольно старомоден. Переключусь на Code128!
Yakovleff