B4J Question Converting a VB Excel Sub to B4J - Help greatly appreciated!

Fr Simon Rundell

Member
Licensed User
Longtime User
Dear Friends,

I am trying to create EAN13 Barcodes (for ISBN Numbers) and have had little joy with other methods using that wrapped barcode class in java but I have made some progress with this method (in Excel anyway) which utilises a special EAN13 font and a sub to create a character chain which the font turns into a working barcode.

Sadly, Maths is not my strong point, and after reading this, you might conclude that programming isn't either... :) and I'm having difficulty translating this Sub into B4x, particularly the maths.
The code was originally written in French, which didn't help my undertsanding. The IDE particularly objects to the Mod functions and subtituting string.CharAt(0) to get the leftmost character makes it very upset. I translated I%, checksum%, first% as Ints and CodeBarre$, Chaine$ as Strings...

Any insights/hints would be appreciated.

B4X:
Public Function ean13$(chaine$)
 '************************MACRO FONCTION EAN13***************************************************
 '************************--------------------***************************************************
 'Parameters: a 12-digit string
    'Return: * a chain which, displayed with the EAN13.TTF font, gives the barcode
    '* an empty string if parameter supplied incorrect
    'Originally in French, comments updated by Google Translate...
    '
  Dim I%, checksum%, first%, CodeBarre$, tableA As Boolean
  ean13$ = ""
  'Check it is 12 chars
  If Len(chaine$) = 12 Then
    'then work through it
    For I% = 1 To 12
      If Asc(Mid$(chaine$, I%, 1)) < 48 Or Asc(Mid$(chaine$, I%, 1)) > 57 Then
        I% = 0
        Exit For
      End If
    Next
    If I% = 13 Then
      'Calcul de la clé de contrôle
      For I% = 2 To 12 Step 2
        checksum% = checksum% + Val(Mid$(chaine$, I%, 1))
      Next
      checksum% = checksum% * 3
      For I% = 1 To 11 Step 2
        checksum% = checksum% + Val(Mid$(chaine$, I%, 1))
      Next
      chaine$ = chaine$ & (10 - checksum% Mod 10) Mod 10
      ''The first number is taken as is, the second comes from table A
      CodeBarre$ = Left$(chaine$, 1) & Chr$(65 + Val(Mid$(chaine$, 2, 1)))
      first% = Val(Left$(chaine$, 1))
      For I% = 3 To 7
        tableA = False
         Select Case I%
         Case 3
           Select Case first%
           Case 0 To 3
             tableA = True
           End Select
         Case 4
           Select Case first%
           Case 0, 4, 7, 8
             tableA = True
           End Select
         Case 5
           Select Case first%
           Case 0, 1, 4, 5, 9
             tableA = True
           End Select
         Case 6
           Select Case first%
           Case 0, 2, 5, 6, 7
             tableA = True
           End Select
         Case 7
           Select Case first%
           Case 0, 3, 6, 8, 9
             tableA = True
           End Select
         End Select
       If tableA Then
         CodeBarre$ = CodeBarre$ & Chr$(65 + Val(Mid$(chaine$, I%, 1)))
       Else
         CodeBarre$ = CodeBarre$ & Chr$(75 + Val(Mid$(chaine$, I%, 1)))
       End If
     Next
      CodeBarre$ = CodeBarre$ & "*"   'add separator character of font
      For I% = 8 To 13
        CodeBarre$ = CodeBarre$ & Chr$(97 + Val(Mid$(chaine$, I%, 1)))
      Next
      CodeBarre$ = CodeBarre$ & "+"   'add final char of font
      ean13$ = CodeBarre$
    End If
  End If
End Function
 

Fr Simon Rundell

Member
Licensed User
Longtime User
Two in particular:

Line 32 - Refusing to cast first=chaine.CharAt(0)
and
Line 29 - Aparrently Modular Math exists, but have not seen the function documented. Unclear as how to translate.

The link you gave has (this time) been more fruitful, and I at least have a barcode. This route might not be needed, as it messes around with fonts which I don't think is that elegant...
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Longtime User
Simon fortunately for your limited knowledge of Maths is not the stumbling block, but not mention of "old Visual Basic" shorthand by Microsoft in Microsoft Docs. In the eighties % sign was used % for an integer, & for Long, ! for single, # for double, and $ for a string text variable.
VBA code:
    Dim count As Int                            ' i%
    Dim counter As Int                         '
    Dim checksum As Int    = 0            ' checksum%
    Dim first As Int = 0                        ' first%
    Dim codeBarre As String = ""       ' codeBarre$
    Dim tableA As Boolean = True    ' tableA
    Dim ean13 As String = ""             ' ean13$

The replacement code for Exit For:
VBA code:
    'Check it is 12 chars
    If chain.Length = 12 Then
        'then work through it
        For counter = 1 To 12
            If Asc(chain.SubString2(counter, 1)) < 48 Or Asc(chain.SubString2(counter, 1)) > 57 Then
                count = 0
'            Exit For  ' Replace trick
                counter = 12
            End If
        Next
        If counter = 13 Then
'      Calculation of the control key
            For counter = 2 To 12 Step 2
'                checksum% = checksum% + Val(Mid$(chaine$, I%, 1))
                Dim temp As String
                temp = chain.SubString(counter-1)
                Dim b() As Byte = temp.GetBytes("UTF8")
                checksum = checksum + b(0)
            Next

I hope this helps you out because my knowledge of EAN barcode is very limited.
 
Upvote 0

emexes

Expert
Licensed User
I am trying to create EAN13 Barcodes (for ISBN Numbers) ... utilises a special EAN13 font
Did you get this working? I suspect that generating an image directly would be more portable and less drama than relying on a special font being installed.

Sadly, Maths is not my strong point, and after reading this, you might conclude that programming isn't either... :)
Lol. Good humor is a prerequisite for good programming, so you've cleared that hurdle ???
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Did you try my old library dgBarCodes? If I'm not wrong it was designed for B4A but if you find it useful and I can find a couple of hours I could publish it as a class .
And, if we are lucky (very lucky) as a B4X class...
It doesn't use any special font. Barcode generation is made by graphical commands (e.g. Drawline).

ps: please consider that I forgot almost everything about that lib, so don't take my words as a promise

Update: I was wrong..eheh. It seems that back in 2015 I already ported the lib to B4J. You can find it here.
As already said, if you find it useful, there's no problem to release it as a class or to try to look for some spare time to further develop it.
 
Last edited:
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
I have the ones for Code128 and Code39 if it can help. It returns the 'string' with checksum to be used by a font.

Note: In Code128 I added 0xF000 everywhere, but this is because the code128.ttf font I use has put it glyps 0xF000 positions further (e.g. char 0x20 is positioned at 0xF020).
Also, this may not work with your font. You will probably have to open it up in a font editor and find out where it has put its glyps. This was in my case my biggest struggle to get this working.

B4X:
Public Sub Code128(SourceString As String) As String 
    Dim Counter As Int
    Dim CheckSum As Long
    Dim mini As Int
    Dim dummy As Int
    Dim UseTableB As Boolean
    Dim Code128_Barcode As String
    Dim mCode128 As String
    Dim aCounter As Int
 
    If SourceString.Length > 0 Then 
        'Check for valid characters
        For Counter = 1 To SourceString.Length
            aCounter = Asc(Mid(SourceString, Counter, 1))
            Select Case True           
                Case (aCounter > 32 And aCounter < 126) Or 203           
                Case Else
           
                    Log("Invalid character in barcode string." & CRLF & CRLF & "Please only use standard ASCII characters")
                    mCode128 = ""
                    Return mCode128           
            End Select       
        Next
   
        Code128_Barcode = ""
        UseTableB = True
   
        Counter = 1
        Do While Counter <= SourceString.Length       
            If UseTableB Then               
                'Check if we can switch to Table C
                If Counter = 1 Or Counter + 3 = SourceString.Length Then
                    mini = 4
                Else
                    mini = 6
                End If   
               
                mini = mini - 1
                If Counter + mini <= SourceString.Length Then   
                    Do While mini >= 0
                        aCounter = Asc(Mid(SourceString, Counter + mini, 1))
                        If aCounter < 48 Or aCounter > 57 Then Exit
                        mini = mini - 1
           
                    Loop       
                End If
               
                If mini < 0 Then 'Use Table C           
                    If Counter = 1 Then               
                        Code128_Barcode = Chr(0xF000 + 205)               
                    Else 'Switch to table C               
                        Code128_Barcode = Code128_Barcode & Chr(0xF000 + 199)                   
                    End If               
                    UseTableB = False           
                Else           
                    If Counter = 1 Then Code128_Barcode = Chr(0xF000 + 204) 'Starting with table B           
                End If           
            End If
       
            If Not(UseTableB) Then           
                'We are using Table C, try to process 2 digits
                mini = 2
                mini = mini - 1
                If Counter + mini <= SourceString.Length Then   
                    Do While mini >= 0
                        aCounter = Asc(Mid(SourceString, Counter + mini, 1))
                        If aCounter< 48 Or aCounter > 57 Then Exit
                        mini = mini - 1           
                    Loop       
                End If
         
                If mini < 0 Then 'OK for 2 digits, process it           
                    dummy = Mid(SourceString, Counter, 2)
                    dummy = IIF(dummy < 95, dummy + 32, dummy + 100)
                    Code128_Barcode = Code128_Barcode & Chr(0xF000 + dummy)
                    Counter = Counter + 2               
                Else 'We haven't got 2 digits, switch to Table B           
                    Code128_Barcode = Code128_Barcode & Chr(0xF000 + 200)
                    UseTableB = True               
                End If       
            End If
       
            If UseTableB Then       
                'Process 1 digit with table B
                Code128_Barcode = Code128_Barcode & Chr(0xF000  + Asc(Mid(SourceString, Counter, 1)))
                Counter = Counter + 1           
            End If       
        Loop
       
        'Calculation of the checksum
        For Counter = 1 To Code128_Barcode.Length       
            dummy = Asc(Mid(Code128_Barcode, Counter, 1)) - 0xF000
            dummy = IIF(dummy < 127, dummy - 32, dummy - 100)
           
            If Counter = 1 Then CheckSum = dummy
               
            CheckSum = (CheckSum + (Counter - 1) * dummy) Mod 103               
        Next
     
        'Calculation of the checksum code
        CheckSum = IIF(CheckSum < 95, CheckSum + 32, CheckSum + 100)
     
        'Add the checksum and the STOP
        Code128_Barcode = Code128_Barcode & Chr(0XF000 + CheckSum) & Chr(0xF000 + 206)
    End If
 
    mCode128 = Code128_Barcode
 
    Return mCode128   
End Sub

Sub IIF(c As Boolean, TrueRes As String, FalseRes As String) As String
    If c Then
        Return TrueRes
    Else
        Return FalseRes
    End If
End Sub

Public Sub Code39(c39 As String) As String 
    Dim Counter As Int
    Dim mCode39 As String
    Dim aCounter As Int
   
    If c39.Length > 0 Then 
        c39 = c39.ToUpperCase
       
        'Check for valid characters
        For Counter = 1 To c39.Length
            aCounter = Asc(Mid(c39, Counter, 1))
            Select Case True       
                Case 32, 36, 37, 43
                Case aCounter >= 45 And aCounter<= 57
                Case aCounter >= 65 And aCounter<= 90
                Case Else           
                    Log("Invalid character in barcode string." & CRLF & CRLF & "Only use 0-9, A-Z, - + . $ % / and the SPACE character")
                    mCode39 = ""
                    Return mCode39           
            End Select       
        Next       
    End If
   
    mCode39 = "*" & c39 & "*"
    Return mCode39
End Sub

Alwaysbusy
 
Upvote 0
Top