A rather long answer, but this does not need any external packages such as tikz or MetaPost. If you want a detailed explanation, you should get the next issue of the TUGBoat or DTK (German). A bonus feature: it will calculate the checksum if not given.
I'll show a picture of the resulting barcode first:

\documentclass[a4paper]{article}
\usepackage{luacode}
\begin{document}
\newcommand\barcodelua[1]{%
\directlua{generate_barcode_lua("#1")}}
\begin{luacode*}
local add_checksum_if_necessary, mkpattern, split_number, calculate_unit, pattern_to_wd_dp
function calculate_unit()
-- The relative widths of a digit represented by the barcode add up to 7.
local currentfont = font.fonts[font.current()]
local digit_zero = currentfont.characters[48]
return digit_zero.width / 7
end
function pattern_to_wd_dp( pattern,pos )
local wd,dp
wd = tonumber(string.sub(pattern,pos,pos))
if wd == 0 then
dp = "2mm"
wd = 1
else
dp = "0mm"
end
return wd,dp
end
function add_checksum_if_necessary( str )
if string.len(str) == 13 then
return str
end
local sum = 0
local len = string.len(str)
for i=len,1,-1 do
if (len - i ) % 2 == 0 then
sum = sum + tonumber(string.sub(str,i,i)) * 3
else
sum = sum + tonumber(string.sub(str,i,i))
end
end
local checksum = (10 - sum % 10) % 10
return str .. tostring(checksum)
end
function mkpattern( str )
-- These are the digits represented by the bars.
local digits_t = {"3211","2221","2122","1411","1132","1231","1114","1312","1213","3112"}
-- The first digit is encoded by the appearance of the
-- next six digits. A value of 1 means that the
-- generated gaps/bars are to be inverted.
local mirror_t = {"------","--1-11","--11-1","--111-","-1--11","-11--1","-111--","-1-1-1","-1-11-","-11-1-"}
-- Convert the digit string into an array.
local number = {}
for i=1,string.len(str) do
number[i] = tonumber(string.sub(str,i,i))
end
-- The first digit in a barcode determines how the next six digit patterns are displayed.
local prefix = table.remove(number,1)
local mirror_str = mirror_t[prefix + 1]
local pattern = "8010"
local digits_str
for i=1,#number do
digits_str = digits_t[number[i] + 1]
if string.sub(mirror_str,i,i) == "1" then
digits_str = string.reverse(digits_str)
end
pattern = pattern .. digits_str
-- The middle two bars.
if i==6 then pattern = pattern .. "10101" end
end
-- Append the right 111 pattern as above.
return pattern .. "010"
end
function split_number( str )
return string.match(str,"(%d)(%d%d%d%d%d%d)(%d%d%d%d%d%d)")
end
local add_to_nodelist, mkrule, mkkern, mkglyph
function generate_barcode_lua( str )
str = add_checksum_if_necessary(str)
local u = calculate_unit()
local nodelist
local pattern = mkpattern(str)
local wd,dp
for i=1,string.len(pattern) do
wd,dp = pattern_to_wd_dp(pattern,i)
if i % 2 == 0 then
nodelist = add_to_nodelist(nodelist,mkrule(wd * u,tex.sp("2cm"),tex.sp(dp)))
else
nodelist = add_to_nodelist(nodelist,mkkern(wd * u))
end
end
local barcode_top = node.hpack(nodelist)
barcode_top = add_to_nodelist(barcode_top,mkkern(tex.sp("-1.7mm")))
-- The following list holds the displayed digits
nodelist = nil
for i,v in ipairs({split_number(str)}) do
for j=1,string.len(v) do
nodelist = add_to_nodelist(nodelist,mkglyph(string.sub(v,j,j)))
end
if i == 1 then
nodelist = add_to_nodelist(nodelist,mkkern(5 * u))
elseif i == 2 then
nodelist = add_to_nodelist(nodelist,mkkern(4 * u))
end
end
local barcode_bottom = node.hpack(nodelist)
barcode_top = add_to_nodelist(barcode_top,barcode_bottom)
local bc = node.vpack(barcode_top)
node.write(bc)
end
function add_to_nodelist( head,entry )
if head then
local tail = node.tail(head)
tail.next = entry
entry.prev = tail
else
head = entry
end
return head
end
function mkrule( wd,ht,dp )
local r = node.new("rule")
r.width = wd
r.height = ht
r.depth = dp
return r
end
function mkkern( wd )
local k = node.new("kern")
k.kern = wd
return k
end
function mkglyph( char )
local g = node.new("glyph")
g.char = string.byte(char)
g.font = font.current()
g.lang = tex.language
return g
end
\end{luacode*}
\barcodelua{4242002518169}
\end{document}