Der Barcode hatte Geburtstag

Letztens hatte der Barcode Geburtstag und die Jungs von Hackaday.com hatten eine kleine Challange aufgesetzt. Es ging darum einen Barcode zu entziffern…
Das hat mein Interesse geweckt! Hier ist meine Lösung dazu und noch zwei Barcodes zum rumspielen… Enjoy =)

wikipedia Barcode

hackaday Barcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/python

import Image
from sys import argv

# lookup tables for the 3 different charsets
CharSetA =  {
    ' ':0, '!':1, '"':2, '#':3, '$':4, '%':5, '&':6, "'":7,
    '(':8, ')':9, '*':10, '+':11, ',':12, '-':13, '.':14, '/':15,
    '0':16, '1':17, '2':18, '3':19, '4':20, '5':21, '6':22, '7':23,
    '8':24, '9':25, ':':26, ';':27, '<':28, '=':29, '>':30, '?':31,
    '@':32, 'A':33, 'B':34, 'C':35, 'D':36, 'E':37, 'F':38, 'G':39,
    'H':40, 'I':41, 'J':42, 'K':43, 'L':44, 'M':45, 'N':46, 'O':47,
    'P':48, 'Q':49, 'R':50, 'S':51, 'T':52, 'U':53, 'V':54, 'W':55,
    'X':56, 'Y':57, 'Z':58, '[':59, '\':60, ']':61, '^':62, '_':63,
    '
\x00':64, '\x01':65, '\x02':66, '\x03':67, '\x04':68, '\x05':69, '\x06':70, '\x07':71,
    '
\x08':72, '\x09':73, '\x0A':74, '\x0B':75, '\x0C':76, '\x0D':77, '\x0E':78, '\x0F':79,
    '
\x10':80, '\x11':81, '\x12':82, '\x13':83, '\x14':84, '\x15':85, '\x16':86, '\x17':87,
    '
\x18':88, '\x19':89, '\x1A':90, '\x1B':91, '\x1C':92, '\x1D':93, '\x1E':94, '\x1F':95,
    '
FNC3':96, 'FNC2':97, 'SHIFT':98, 'Code C':99, 'Code B':100, 'FNC4':101, 'FNC1':102, 'START A':103,
    '
START B':104, 'START C':105, ' STOP':106
}

CharSetB = {
    '
':0, '!':1, '"':2, '#':3, '$':4, '%':5, '&':6, "'":7,
    '
(':8, ')':9, '*':10, '+':11, ',':12, '-':13, '.':14, '/':15,
    '
0':16, '1':17, '2':18, '3':19, '4':20, '5':21, '6':22, '7':23,
    '
8':24, '9':25, ':':26, ';':27, '<':28, '=':29, '>':30, '?':31,
    '
@':32, 'A':33, 'B':34, 'C':35, 'D':36, 'E':37, 'F':38, 'G':39,
    '
H':40, 'I':41, 'J':42, 'K':43, 'L':44, 'M':45, 'N':46, 'O':47,
    '
P':48, 'Q':49, 'R':50, 'S':51, 'T':52, 'U':53, 'V':54, 'W':55,
    '
X':56, 'Y':57, 'Z':58, '[':59, '\':60, ']':61, '^':62, '_':63,
    '
' :64, 'a':65, 'b':66, 'c':67, 'd':68, 'e':69, 'f':70, 'g':71,
    '
h':72, 'i':73, 'j':74, 'k':75, 'l':76, 'm':77, 'n':78, 'o':79,
    '
p':80, 'q':81, 'r':82, 's':83, 't':84, 'u':85, 'v':86, 'w':87,
    '
x':88, 'y':89, 'z':90, '{':91, '|':92, '}':93, '~':94, '\x7F':95,
    '
FNC3':96, 'FNC2':97, 'SHIFT':98, 'Code C':99, 'FNC4':100, 'Code A':101, 'FNC1':102, 'START A':103,
    '
START B':104, 'START C':105, ' STOP':106
}

CharSetC = {
    '
00':0, '01':1, '02':2, '03':3, '04':4, '05':5, '06':6, '07':7,
    '
08':8, '09':9, '10':10, '11':11, '12':12, '13':13, '14':14, '15':15,
    '
16':16, '17':17, '18':18, '19':19, '20':20, '21':21, '22':22, '23':23,
    '
24':24, '25':25, '26':26, '27':27, '28':28, '29':29, '30':30, '31':31,
    '
32':32, '33':33, '34':34, '35':35, '36':36, '37':37, '38':38, '39':39,
    '
40':40, '41':41, '42':42, '43':43, '44':44, '45':45, '46':46, '47':47,
    '
48':48, '49':49, '50':50, '51':51, '52':52, '53':53, '54':54, '55':55,
    '
56':56, '57':57, '58':58, '59':59, '60':60, '61':61, '62':62, '63':63,
    '
64':64, '65':65, '66':66, '67':67, '68':68, '69':69, '70':70, '71':71,
    '
72':72, '73':73, '74':74, '75':75, '76':76, '77':77, '78':78, '79':79,
    '
80':80, '81':81, '82':82, '83':83, '84':84, '85':85, '86':86, '87':87,
    '
88':88, '89':89, '90':90, '91':91, '92':92, '93':93, '94':94, '95':95,
    '
96':96, '97':97, '98':98, '99':99, 'Code B':100, 'Code A':101, 'FNC1':102, 'START A':103,
    '
START B':104, 'START C':105, ' STOP':106
}

# The barcode and the according number in the according char-set
ValueEncodings = {
    0:'
11011001100',  1:'11001101100',  2:'11001100110',
    3:'
10010011000',  4:'10010001100',  5:'10001001100',
    6:'
10011001000',  7:'10011000100',  8:'10001100100',
    9:'
11001001000', 10:'11001000100', 11:'11000100100',
    12:'
10110011100', 13:'10011011100', 14:'10011001110',
    15:'
10111001100', 16:'10011101100', 17:'10011100110',
    18:'
11001110010', 19:'11001011100', 20:'11001001110',
    21:'
11011100100', 22:'11001110100', 23:'11101101110',
    24:'
11101001100', 25:'11100101100', 26:'11100100110',
    27:'
11101100100', 28:'11100110100', 29:'11100110010',
    30:'
11011011000', 31:'11011000110', 32:'11000110110',
    33:'
10100011000', 34:'10001011000', 35:'10001000110',
    36:'
10110001000', 37:'10001101000', 38:'10001100010',
    39:'
11010001000', 40:'11000101000', 41:'11000100010',
    42:'
10110111000', 43:'10110001110', 44:'10001101110',
    45:'
10111011000', 46:'10111000110', 47:'10001110110',
    48:'
11101110110', 49:'11010001110', 50:'11000101110',
    51:'
11011101000', 52:'11011100010', 53:'11011101110',
    54:'
11101011000', 55:'11101000110', 56:'11100010110',
    57:'
11101101000', 58:'11101100010', 59:'11100011010',
    60:'
11101111010', 61:'11001000010', 62:'11110001010',
    63:'
10100110000', 64:'10100001100', 65:'10010110000',
    66:'
10010000110', 67:'10000101100', 68:'10000100110',
    69:'
10110010000', 70:'10110000100', 71:'10011010000',
    72:'
10011000010', 73:'10000110100', 74:'10000110010',
    75:'
11000010010', 76:'11001010000', 77:'11110111010',
    78:'
11000010100', 79:'10001111010', 80:'10100111100',
    81:'
10010111100', 82:'10010011110', 83:'10111100100',
    84:'
10011110100', 85:'10011110010', 86:'11110100100',
    87:'
11110010100', 88:'11110010010', 89:'11011011110',
    90:'
11011110110', 91:'11110110110', 92:'10101111000',
    93:'
10100011110', 94:'10001011110', 95:'10111101000',
    96:'
10111100010', 97:'11110101000', 98:'11110100010',
    99:'
10111011110',100:'10111101110',101:'11101011110',
    102:'
11110101110',103:'11010000100',104:'11010010000',
    105:'
11010011100',106:'11000111010'
}# '


# swap the dictionaries
def swap_dictionary(original_dict):
    # old version
#   return dict( [(v, k) for (k, v) in original_dict.iteritems()] )
    # refined version... with generator expressions...thx J
    return dict( (v, k) for (k, v) in original_dict.iteritems() )

# I found these encoding tables on the web...
# sadly the key:value pairs are the wrong way for my need
# so i swap them =)
CharSetA = swap_dictionary(CharSetA)
CharSetB = swap_dictionary(CharSetB)
CharSetC = swap_dictionary(CharSetC)
ValueEncodings = swap_dictionary(ValueEncodings)


# read in image
im_file = Image.open(argv[1])
im = im_file.getdata()
width = im.size[0]
height = im.size[1] / 2

# convert to 1 pixel high stripe in the middle of the image
cropped = im.crop((0,height,width,height+1))

# translate to 0's and 1's
code = ''
for pixel in cropped:
    try: # if is RGB picture
        pix = pixel[0]
    except: # if is greyscale picture
        pix = pixel
    if pix >200:
        pix = 0
    else:
        pix = 1
    code += str(pix)


# remove leading and trailing 0's
code = code.lstrip('0').rstrip('0')
   
   
# pop first 11 bits from the code
# these 11 bits stand for a char
def get_char(code):
    char = code[:11]
    code = code[11:]
    return char, code


out_buff = ""
# determine the encoding
first, code = get_char(code)
encoding = ValueEncodings[first]

if encoding == 103:
    charset = CharSetA
    out_buff += 'START A '
elif encoding == 104:
    charset = CharSetB
    out_buff += 'START B '
elif encoding == 105:
    charset = CharSetC
    out_buff += 'START C '
else:
    print "Encoding unknown"
    exit(0)


# decypher the message
while(len(code) >= 11):
    next_char, code = get_char(code)
    encoding_number = ValueEncodings[next_char]
    out_buff += charset[encoding_number]

# display the message
print out_buff

Einfach als barcode.py speichern und von der Konsole aus mit:

1
python barcode.py BarcodeBild.jpg

starten. Das Ganze funktiniert allerdings nur unter bestimmten Voraussetzungen. Der Barcode muss vom Typ 128 sein und das Bild des Barcodes muss eine 1 mit einem ein Pixel breiten Strich kodieren.

2 Responses to “Der Barcode hatte Geburtstag”

  1. Jorn says:

    Hi, netter hack ;)

    Python unterstützt übrigens mittlerweile Generator-Expressions:
    d = {1:2, 2:3, 3:4}
    inv_d = dict([v,k] for [v,k] in d.iteritems())

    Der kleine aber feine Unterschied ist, dass dein code temporär die komplette Liste der Dict-Pairs nochmal im RAM baut, was bei großen Sachen schief gehen kann. (Du benutzt zwar d.iteritems(), umgehst aber den Sinn.)

    Viele Grüße,
    Jorn

  2. admin says:

    Nice!

    aber kleiner typo hier:
    inv_d = dict([v,k] for [v,k] in d.iteritems())
    müsste so heissen:
    inv_d = dict([k,v] for [v,k] in d.iteritems())
    …also einmal key/value umdrehn.
    Aber gut zu wissen! Danke =)

Leave a Reply