0% found this document useful (0 votes)
4 views

Modul Aztec

The document contains a VBA module for generating Aztec barcodes in Excel, adhering to ISO/IEC 24778:2008 standards. It includes a function that encodes text into an Aztec barcode, with optional parameters for security and layers, and handles the layout and formatting of the barcode within an Excel cell. The code also includes error handling and character encoding logic to ensure proper barcode generation.

Uploaded by

José Sánchez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Modul Aztec

The document contains a VBA module for generating Aztec barcodes in Excel, adhering to ISO/IEC 24778:2008 standards. It includes a function that encodes text into an Aztec barcode, with optional parameters for security and layers, and handles the layout and formatting of the barcode within an Excel cell. The code also includes error handling and character encoding logic to ensure proper barcode generation.

Uploaded by

José Sánchez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

Attribute VB_Name = "ModulAztec"

Option Explicit
Dim typ As Long, enc(1665) As Integer
Dim md As Long, eb As Long, el As Long, b As Long

' Aztec bar code symbol creation according ISO/IEC 24778:2008


' param text to encode
' param security optional: percentage of checkwords used for security 2%-90% (23%)
' param layers optional: number of layers (size), default autodetect, 0 - Aztec
rune
' creates Actec and compact Aztec bar code symbol as shape in Excel cell.
Public Function Aztec(text As String, Optional security As Integer, Optional layers
As Integer = 1) As String
Attribute Aztec.VB_Description = "Draw Aztec barcode"
Attribute Aztec.VB_ProcData.VB_Invoke_Func = " \n18"
Dim fColor As Long, bColor As Long, line As Long, shp As Shape, txt As String
Dim x As Long, y As Long, dx As Long, dy As Long, ctr As Long, ec As Long
Dim c As Long, i As Long, j As Long, k As Long, l As Long, m As Long

On Error GoTo failed


If Not TypeOf Application.Caller Is Range Then Err.Raise 513, "Aztec code", "Call
only from sheet"
fColor = vbBlack: bColor = vbBlack: line = xlHairline ' redraw graphic ?
For Each shp In Application.Caller.Parent.Shapes
If shp.Name = Application.Caller.Address Then
If shp.Title = text Then Exit Function ' same as prev ?
fColor = shp.Fill.ForeColor.RGB ' remember format
bColor = shp.line.ForeColor.RGB
line = shp.line.Weight
shp.Delete
End If
Next shp
If security < 1 Then security = 23 Else If security > 90 Then security = 90
txt = IIf(text = "", " ", utf16to8(text)) ' at least 1 char
el = Len(txt): x = 4: typ = 0
Do ' compute word size b: 6/8/10/12 bits
i = Int(el * 100 / (100 - security) + 3) * x ' needed bits, at least 3
checkwords
If i > l Then l = i
b = IIf(l <= 240, 6, IIf(l <= 1920, 8, IIf(l <= 10208, 10, 12))) ' bit capacity
-> word size
i = IIf(layers < 3, 6, IIf(layers < 9, 8, IIf(layers < 23, 10, 12))) ' layer
paramerter
If i > b Then b = i
If x >= b Then Exit Do
el = 0: md = 0: eb = 0: enc(0) = 0 ' clr bit stream
For i = 1 To Len(txt) ' scan text
c = Asc(Mid(txt, i, 1)): k = 0
If i < Len(txt) Then k = Asc(Mid(txt, i + 1, 1))
If c = 32 Then ' space
If md = 3 Then push 31: md = 0 ' punct: latch to upper
c = 1 ' space in all other modes
ElseIf md = 4 And c = 44 Then
c = 12 ' , in digit mode
ElseIf md = 4 And c = 46 Then
c = 13 ' . in digit mode
ElseIf ((c = 44 Or c = 46 Or c = 58) And k = 32) Or (c = 13 And k = 10)
Then
If md <> 3 Then push (0) ' shift to punct
push IIf(c = 46, 3, IIf(c = 44, 4, IIf(c = 58, 5, 2))) ' two char
encoding
i = i + 1: GoTo continue
Else
c = IIf(c = 13 And modeOf(k) \ 32 = md, 97, modeOf(c))
If c < 0 Then ' binary
If md > 2 Then push IIf(md = 3, 31, 14): md = 0 ' latch to upper
j = 0: push 31 ' shift to binary
For k = 0 To Len(txt) - i - 1 ' calc binary length
If modeOf(Asc(Mid(txt, k + i, 1))) < 0 Then
j = 0
Else
j = j + 1
If j > 5 Then Exit For ' look for at least 5 consecutive
non binary chars
End If
Next k
k = k - j
If k > 30 Then
push 0: push k - 30, 11
Else
push k + 1
End If
For j = 0 To k ' encode binary data
push Asc(Mid(txt, i + j, 1)), 8
If el > 1660 Then Exit For
Next j
i = i + k: GoTo continue
End If
m = c \ 32 ' needed mode
If m = 4 And md = 2 Then push 29: md = 0 ' mixed to upper (to digit)
If m <> 3 And md = 3 Then push 31: md = 0 ' exit punct: to upper
If m <> 4 And md = 4 Then ' exit digit
If (m = 3 Or m = 0) And modeOf(k) > 129 Then
push (3 - m) * 5: push c And 31, 5 ' shift to punct/upper
GoTo continue
End If
push 14: md = 0 ' latch to upper
End If
If md <> m Then ' mode change needed
If m = 3 Then ' to punct
If md <> 4 And modeOf(k) \ 32 = 3 Then ' 2x punct, latch to
punkt
If md <> 2 Then push 29 ' latch to mixed
push 30 ' latch to punct
md = 3 ' mode punct
Else
push 0 ' shift to punct
End If
ElseIf md = 1 And m = 0 Then ' lower to upper
If modeOf(k) \ 32 = 1 Then
push 28 ' shift
Else
push 30: push 14, 4 ' latch
md = 0
End If
Else ' latch to ..
push Array(29, 28, 29, 30, 30)(m)
md = m
End If
End If
End If
push c And 31 ' add char
If el > 1660 Then Exit For
continue:
Next i
push 2 ^ (b - eb) - 1, b - eb ' add padding bits
x = b
Loop
If el > 1660 Then Err.Raise 514, "Aztec code", "Message too long."
typ = IIf(l > 608 Or el > 64, 14, 11) ' full or compact Aztec
md = val(Left(txt, 3)) ' Aztec rune possible ?
If md < 0 Or md > 255 Or md & "" <> txt Or layers > 0 Then
i = -Int((typ - Sqr(l + typ * typ)) / 4) ' needed layers
If i > layers Then layers = i
If layers > 32 Then layers = 32
End If
ec = (8 * layers * (typ + 2 * layers)) \ b - el ' # of checkwords
typ = typ \ 2: ctr = typ + 2 * layers: ctr = ctr + (ctr - 1) \ 15 ' center position
security = 100 * ec / (el + ec)

With Application.Caller.Parent.Shapes ' layout Aztec barcode


m = .Count + 1
For y = 1 - typ To typ - 1 ' layout central finder
For x = 1 - typ To typ - 1
If (IIf(Abs(x) > Abs(y), x, y) And 1) = 0 Then
.AddShape(msoShapeRectangle, ctr + x, ctr + y, 1, 1).Name =
Application.Caller.Address
End If
Next x
Next y
For i = 0 To 5 ' orientation marks
x = Array(-typ, -typ, 1 - typ, typ, typ, typ)(i)
y = Array(1 - typ, -typ, -typ, typ - 1, 1 - typ, -typ)(i)
.AddShape(msoShapeRectangle, ctr + x, ctr + y, 1, 1).Name =
Application.Caller.Address
Next i
If layers > 0 Then ' layout data
addCheck ec, 2 ^ b - 1, Array(67, 301, 1033, 4201)(b / 2 - 3) ' error
correction, generator polynomial
x = -typ: y = x - 1 ' start of layer 1 at top left
j = (3 * typ + 11) / 2: l = j ' length of inner side
dx = 1: dy = 0 ' direction right
For ec = ec + el - 1 To 0 Step -1 ' layout codeword
c = enc(ec) ' data in reversed order inside to outside
For i = 1 To b / 2
If c And 1 Then ' odd bit
.AddShape(msoShapeRectangle, ctr + x, ctr + y, 1, 1).Name =
Application.Caller.Address
End If
move x, y, dy, -dx ' move across
If c And 2 Then ' even bit
.AddShape(msoShapeRectangle, ctr + x, ctr + y, 1, 1).Name =
Application.Caller.Address
End If
move x, y, dx - dy, dx + dy ' move ahead
j = j - 1
If j = 0 Then ' spiral turn
move x, y, dy, -dx ' move across
j = dx: dx = -dy: dy = j ' rotate clockwise
If dx < 1 Then
move x, y, dx - dy, dx + dy ' move ahead
move x, y, dx - dy, dx + dy ' move ahead
Else
l = l + 4 ' full turn -> next layer
End If
j = l ' start new side
End If
c = c \ 4
Next i
Next ec
If typ = 7 Then ' layout reference grid
For x = (15 - ctr) And -16 To ctr Step 16
For y = (1 - ctr) And -2 To ctr Step 2
If Abs(x) > typ Or Abs(y) > typ Then
.AddShape(msoShapeRectangle, ctr + x, ctr + y, 1, 1).Name =
Application.Caller.Address ' down
If y And 15 Then
.AddShape(msoShapeRectangle, ctr + y, ctr + x, 1,
1).Name = Application.Caller.Address ' across
End If
End If
Next y
Next x
End If
md = (layers - 1) * (typ * 992 - 4896&) + el - 1 ' 2/5 + 6/11 mode bits
End If
el = typ - 3 ' process modes message compact/full
For i = el - 1 To 0 Step -1
enc(i) = md And 15 ' mode to 4 bit words
md = md \ 16
Next i
addCheck typ \ 2 + 3, 15, 19 ' add 5/6 words error correction
el = el + typ \ 2 + 3 ' init bit stream
b = (typ * 3) \ 2 ' 7/10 bits per side
eb = 0: j = IIf(layers, 0, 10) 'XOR Aztec rune data
For i = 0 To b - 1
push j Xor enc(i), 4 ' 8/16 words to 4 chunks
Next i
j = 1 ' layout mode data
For i = 2 - typ To typ - 2
If typ = 7 And i = 0 Then i = i + 1 ' skip reference grid
If enc(b) And j Then .AddShape(msoShapeRectangle, ctr - i, ctr - typ, 1,
1).Name = Application.Caller.Address ' top
If enc(b + 1) And j Then .AddShape(msoShapeRectangle, ctr + typ, ctr - i,
1, 1).Name = Application.Caller.Address ' right
If enc(b + 2) And j Then .AddShape(msoShapeRectangle, ctr + i, ctr + typ,
1, 1).Name = Application.Caller.Address ' bottom
If enc(b + 3) And j Then .AddShape(msoShapeRectangle, ctr - typ, ctr + i,
1, 1).Name = Application.Caller.Address ' left
j = j + j
Next i
m = .Count - m
ReDim shps(m) As Integer ' group all shapes
For i = .Count To 1 Step -1
If .Range(i).Name = Application.Caller.Address Then
shps(m) = i: m = m - 1
If m < 0 Then Exit For
End If
Next i
With .Range(shps).Group
.Fill.ForeColor.RGB = fColor ' format barcode shape
.line.ForeColor.RGB = bColor
.line.Weight = line
x = Application.Caller.MergeArea.Width
y = Application.Caller.MergeArea.Height
If x > y Then x = y
.Width = x * (2 * ctr + 1) / (2 * ctr + 3) ' fit symbol in excel cell
.Height = .Width
.Left = Application.Caller.Left + (Application.Caller.MergeArea.Width
- .Width) / 2
.Top = Application.Caller.Top + (Application.Caller.MergeArea.Height
- .Height) / 2
.Name = Application.Caller.Address ' link shape to data
.Title = text
.AlternativeText = "Aztec " & IIf(typ = 5, "compact", "full") & " barcode,
security " & security & "%, layers " & layers & ", " & (2 * ctr + 1) & "x" & (2 *
ctr + 1) & " cells"
.LockAspectRatio = True
.Placement = xlMove
End With
End With
failed:
If Err.Number Then Aztec = "ERROR Aztec: " & Err.Description
End Function

' get character encoding mode of ch


Private Function modeOf(ByVal ch As Integer) As Integer
Dim i As Integer, k As Variant
If ch = 32 Then modeOf = md * 32: Exit Function ' space
k = Array(0, 14, 65, 26, 32, 52, 32, 48, 69, 47, 58, 82, 57, 64, 59, 64, 91, -63,
96, 123, -63)
For i = 0 To UBound(k) Step 3 ' check range
If ch > k(i) And ch < k(i + 1) Then Exit For
Next i
If i <= UBound(k) Then modeOf = ch + k(i + 2): Exit Function ' ch in range
i = InStr("@\^_'|~�[]{}", Chr(ch))
modeOf = IIf(i = 0, -1, IIf(i < 9, 20 + 64, 27 + 96 - 8) + i - 1) '
binary/mixed/punct
End Function

' add value to data stream


Private Sub push(ByVal val As Long, Optional ByVal bits As Integer = 0)
val = val * 2 ^ b
If bits = 0 Then bits = IIf(md = 4, 4, 5)
eb = eb + bits
enc(el) = enc(el) + val \ 2 ^ eb ' add data
Do While eb >= b ' word full ?
If typ = 0 And (enc(el) < 2 Or enc(el) + 3 > 2 ^ b) Then ' bit stuffing
enc(el) = enc(el) Xor ((enc(el) + 3) \ 2 And 1) ' add complementary bit
eb = eb + 1
End If
eb = eb - b: el = el + 1
enc(el) = (val \ 2 ^ eb) And ((2 ^ b) - 1)
Loop
End Sub
' compute Reed Solomon error detection and correction
Private Sub addCheck(ByVal ec As Integer, ByVal s As Integer, ByVal p As Integer)
Dim i As Integer, j As Integer, x As Integer
ReDim rc(ec + 2) As Integer, lg(s + 1) As Integer, ex(s) As Integer
j = 1
For i = 0 To s - 1 ' compute log/exp table of Galois field
ex(i) = j: lg(j) = i
j = j + j: If (j > s) Then j = j Xor p ' GF polynomial
Next i
rc(ec + 1) = 0
For i = 0 To ec ' compute RS generator polynomial
rc(ec - i) = 1
For j = ec - i + 1 To ec
rc(j) = rc(j + 1) Xor ex((lg(rc(j)) + i) Mod s)
Next j
enc(el + i) = 0
Next i
For i = 0 To el - 1 ' compute RS checkwords
x = enc(el) Xor enc(i)
For j = 1 To ec
enc(el + j - 1) = enc(el + j) Xor IIf(x, ex((lg(rc(j)) + lg(x)) Mod s), 0)
Next j
Next i
End Sub

' move one cell


Private Sub move(x As Long, y As Long, ByVal dx As Integer, ByVal dy As Integer)
Do
x = x + dx
Loop While typ = 7 And (x And 15) = 0 ' skip reference grid
Do
y = y + dy
Loop While typ = 7 And (y And 15) = 0
End Sub

You might also like