Created
March 14, 2012 10:25
-
-
Save pgundlach/2035612 to your computer and use it in GitHub Desktop.
Strichcodes mit LuaTeX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module(...,package.seeall) | |
local add_checksum_if_necessary, mkpattern, split_number, calculate_unit, pattern_to_wd_dp | |
function generate_barcode(str) | |
-- Wenn nur 12 Ziffern übergeben werden, fügen wir die 13 hinzu | |
str = add_checksum_if_necessary(str) | |
-- Die kleinste Lücke / Strich ist ein siebtel der Breite einer Ziffer und damit | |
-- abhängig von der Schriftart | |
local u = calculate_unit() | |
-- Wir fangen mit der hbox für die Striche an: | |
tex.sprint([[\newbox\barcodebox\setbox\barcodebox\hbox{%]]) | |
-- Das Muster (pattern) ist eine Zeichenkette von Ziffern, die die Breite eines Striches bzw. | |
-- einer Lücke repräsentieren. 0 ist eine spezielle Markierung, die einen längeren Strich | |
-- der Breite 1 bezeichnet. Die Breiten werden mit 1/7 der Ziffernbreite multipliziert, da | |
-- die Summe der Striche / Lücken für eine Ziffer insgesamt 7 Einheiten breit sind. | |
-- Ein Beispiel-Muster fängt an mit | |
-- 80103211112312132113231132111010132... | |
local pattern = mkpattern(str) | |
-- Für jeden Eintrag im Muster erzeugen wir eine Lücke oder einen Balken mit der Breite, | |
-- die im Eintrag angegeben ist. Eine Tiefe > 0 wird für die Balken am Rand und in der Mitte | |
-- des Strichcodes benutzt. Es gibt keine technische Notwendigkeit dafür, aber es hat | |
-- sich eingebürgert den Strichcode so darzustellen. | |
local wd,dp -- Breite und Tiefe eines Strichs | |
for i=1,string.len(pattern) do | |
wd,dp = pattern_to_wd_dp(pattern,i) | |
-- Die geraden Einträge sind die Länge eines Strichs (vrule), die ungerade der Lücken (kern). | |
if i % 2 == 0 then | |
tex.sprint( | |
string.format([[\vrule width %dsp height 2cm depth %s]],wd * u,dp)) | |
else | |
tex.sprint(string.format([[\kern %dsp]],wd * u)) | |
end | |
end | |
-- Wir haben nun die hbox mit den Strichen und erzeugen nun die hbox mit den Ziffern. | |
tex.sprint( | |
[[}\vbox{\hsize\wd\barcodebox\box\barcodebox\kern -1.7mm\hbox{%]] | |
) | |
-- Die Ziffern Unterhalb des Strichcodes werden in drei Teile getrennt. Eine vor dem ersten Strich, | |
-- die erste Hälfte links und die zweite Hälfte rechts von dem mittleren Strich. | |
local first,second,third = split_number(str) | |
tex.sprint( | |
string.format( | |
[[%s\kern %dsp %s\kern %dsp%s}}]],first, 5 * u, second, 4 * u, third )) | |
end | |
function calculate_unit() | |
-- Die relativen Breiten der Striche und Lücken in einer Ziffer summieren sich zu 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) | |
-- Die Ziffern 0-9 werden durch diese Striche/Lücken dargestellt. 3211 beispielsweise | |
-- bedeutet: Lücke von 3 Einheiten, Strich von 2 Einheiten Breite und eine Lücke und ein | |
-- Strich von jeweils einer Einheit. | |
local digits_t = {"3211","2221","2122","1411","1132","1231","1114","1312","1213","3112"} | |
-- Die erste Ziffer wird durch die Darstellung der nächsten sechs Ziffern kodiert. Ein Eintrag | |
-- von 1 bedeutet, dass die erzeugten Striche / Lücken umgekehrt werden müssen. | |
local mirror_t = {"------","--1-11","--11-1","--111-","-1--11", "-11--1","-111--","-1-1-1","-1-11-","-11-1-"} | |
-- Die Zeichenkette aus Ziffern wird in ein Feld konvertiert. | |
local number = {} | |
for i=1,string.len(str) do | |
number[i] = tonumber(string.sub(str,i,i)) | |
end | |
-- Die erste Ziffer bestimmt, wie die nächsten sechs dargestellt werden. | |
local prefix = table.remove(number,1) | |
local mirror_str = mirror_t[prefix + 1] | |
-- Die Variable pattern wird das erzeugte Muster speichern. Es wird mit der Lücke für die erste | |
-- Ziffer angefangen, anschließend kommt die linke Begrenzung 111 bzw. hier als 010 für die | |
-- Kodierung der längeren Striche angegeben. | |
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 | |
-- Die mittleren beiden Striche | |
if i==6 then pattern = pattern .. "10101" end | |
end | |
-- Das Muster 111 rechts anfügen. | |
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 | |
-- Die geraden Einträge sind die Linien, die ungeraden die Lücken | |
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 | |
-- barcode_top wird die vbox aus der ersten Lösung | |
local barcode_top = node.hpack(nodelist) | |
barcode_top = add_to_nodelist(barcode_top,mkkern(tex.sp("-1.7mm"))) | |
-- Die folgende Liste enthält die dargestellten Ziffern | |
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 hat nun drei Einträge: die hbox mit den Linien und Kerns, das Kern | |
-- mit der Größe -1.7mm und die hbox mit den Ziffern unterhalb der Striche | |
barcode_top = add_to_nodelist(barcode_top,barcode_bottom) | |
local bc = node.vpack(barcode_top) | |
-- node.write() schreibt die vbox in die PDF Datei | |
node.write(bc) | |
end | |
function add_to_nodelist( head,entry ) | |
if head then | |
-- Den Eintrag 'entry' an die Nodeliste anhängen und die prev/next Zeiger anpassen. | |
local tail = node.tail(head) | |
tail.next = entry | |
entry.prev = tail | |
else | |
-- Keine Nodeliste vorhanden, also wird einfach der Eintrag zur Nodeliste | |
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\ProvidesPackage{ltxbarcode} | |
\directlua{require("ltxbarcode")} | |
\newcommand\barcode[1]{% | |
\directlua{ltxbarcode.generate_barcode("\luatexluaescapestring{#1}")}} | |
\newcommand\barcodelua[1]{% | |
\directlua{ltxbarcode.generate_barcode_lua("#1")}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\documentclass{article} | |
\usepackage{ltxbarcode} | |
\begin{document} | |
\barcode{424200251816} | |
% oder, mit Prüfziffer: | |
\barcode{4242002518169} | |
\end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment