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.
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 ratings0% 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.
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