#!/usr/bin/python from PIL import Image def invert(value): return ''.join(["1" if x == "0" else "0" for x in value]) # Load Image im = Image.open('QR3C_cropped.png') pix = im.load() tiles = 21 tileSize = im.size[0] // tiles version = (tiles - 17) // 4 print("tiles=%d tileSize=%d version=%d" % (tiles, tileSize, version)) # Data Array data = [[0 for x in range(tiles)] for y in range(tiles)] # Fill data # Black -> 111 # White -> 000 # Blue -> 110 ... for y in range(tiles): for x in range(tiles): x_mid = x * tileSize + 0.5 * tileSize y_mid = y * tileSize + 0.5 * tileSize color = pix[x_mid, y_mid] data[x][y] = invert("%d%d%d" % ( color[0] // 255, color[1] // 255, color[2] // 255 )) def blackWhiteValue(string): new_value = "" if len(string) % 3 != 0: print("Cannot return black white value of", string) return new_value for i in range(len(string) // 3): new_value += string[i * 3] return new_value mask1 = [data[8][18], data[8][17], data[8][16]] mask2 = [data[2][8], data[3][8], data[4][8]] if mask1 != mask2: print("masks do not match") exit() mask = [''.join(mask1[i][j] for i in range(3)) for j in range(3)] print("Mask:", mask) def apply_mask(x, y, bit, mask): doInvert = False if mask == "111": doInvert = x % 3 == 0 elif mask == "110": doInvert = (x + y) % 3 == 0 elif mask == "101": doInvert = (x + y) % 2 == 0 elif mask == "100": doInvert = y % 2 == 0 elif mask == "000": doInvert = ((x*y) % 2) + ((x + y) % 3) == 0 return invert(bit) if doInvert else bit def get_masked_value(x, y): return ''.join([apply_mask(x, y, data[x][y][i], mask[i]) for i in range(3)]) def read_block(x, y, orientation): indizes = [] if orientation == "UP": indizes = [[0,0], [-1,0], [0,-1], [-1,-1], [0,-2], [-1,-2], [0, -3], [-1, -3]] elif orientation == "LEFT_TOP": indizes = [[0,0], [-1,0], [0,-1], [-1,-1], [-2,-1], [-3,-1], [-2, 0], [-3, 0]] elif orientation == "DOWN": indizes = [[0,0], [-1,0], [0,1], [-1,1], [0,2], [-1,2], [0, 3], [-1, 3]] elif orientation == "LEFT_BOTTOM": indizes = [[0,0], [-1,0], [0,1], [-1,1], [-2,1], [-3,1], [-2, 0], [-3, 0]] return (''.join([get_masked_value(x + offset[0], y + offset[1]) for offset in indizes])) def map_alphanumeric(x): if x < 10: return chr(ord('0') + x) elif x < 36: return chr(ord('A') + x - 10) else: special = { 36: " ", 37: "$", 38: "%", 39: "*", 40: "+", 41: "-", 42: ".", 43: "/", 44: ":" } if x in special: return special[x] else: print("unknown special character:", x) return "?" def decode_alphanumeric(x): a = x // 45 b = x % 45 return map_alphanumeric(a) + map_alphanumeric(b) encoding = blackWhiteValue(data[20][20] + data[19][20] + data[20][19] + data[19][19]) # encoding = data[20][20] + data[19][20] + data[20][19] + data[19][19] # encoding = [get_masked_value(20, 20), get_masked_value(19, 20), get_masked_value(20, 19), get_masked_value(19, 19)] print("Encoding:", encoding) len_block = read_block(20, 18, "UP") print("Length:", int(len_block, 2)) # 19 Blocks blocks = ''.join([ read_block(20, 14, "UP"), read_block(20, 10, "LEFT_TOP"), read_block(18, 11, "DOWN"), read_block(18, 15, "DOWN"), read_block(18, 19, "LEFT_BOTTOM"), read_block(16, 18, "UP"), read_block(16, 14, "UP"), read_block(16, 10, "LEFT_TOP"), read_block(14, 11, "DOWN"), read_block(14, 15, "DOWN") ]) channels = ["", "", ""] blockSize = 3 for i in range(len(blocks) // blockSize): channels[0] += blocks[i*3] channels[1] += blocks[i*3+1] channels[2] += blocks[i*3+2] # chunk = int(blocks[blockSize*i:blockSize*i+blockSize],2) # string += chr(chunk) # string += decode_alphanumeric(chunk) line = "" for c in channels: for i in range(len(c) // 8): line += chr(int(c[i*8:i*8+8], 2)) print(line) # print(len(blocks) /8) # print(''.join(blocks)) # for x in range(tiles): # print(''.join(data[x]))