5D_Heredero_Louis_TM2022/python/qr_generator.py

890 lines
27 KiB
Python
Raw Permalink Normal View History

2022-09-22 11:13:15 +00:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import pygame
import time
S_EMPTY = 1
S_SEP = 2
S_FINDER = 4
S_ALIGN = 8
S_TIMING = 16
S_RESERVED = 32
S_DATA = 64
S_BYTES = 128
S_MASK = 256
STEPS = S_MASK|S_DATA|S_BYTES|S_RESERVED|S_ALIGN|S_TIMING|S_FINDER|S_SEP|S_EMPTY
#STEPS = S_MASK|S_RESERVED|S_ALIGN|S_TIMING|S_FINDER|S_EMPTY
#STEPS = 0
#STEPS = S_MASK|S_DATA
pygame.init()
font = pygame.font.SysFont("ubuntu", 16)
win = None
coords = True # turn on coordinates
def log(msg):
print(f"<[---]> {msg} <[---]>")
class GF:
"""Galois field element"""
def __init__(self, val):
self.val = val
def copy(self):
return GF(self.val)
# Addition
def __add__(self, n):
return GF(self.val ^ n.val)
# Subtraction
def __sub__(self, n):
return GF(self.val ^ n.val)
# Multiplication
def __mul__(self, n):
if self.val == 0 or n.val == 0:
return GF(0)
return GF.EXP[GF.LOG[self.val].val + GF.LOG[n.val].val].copy()
# Division
def __truediv__(self, n):
if n.val == 0:
raise ZeroDivisionError
if self.val == 0:
return GF(0)
return GF.EXP[(GF.LOG[self.val].val + 255 - GF.LOG[n.val].val)%255].copy()
# Power
def __pow__(self, n):
return GF.EXP[(GF.LOG[self.val].val * n.val)%255].copy()
# Representation -> string
def __repr__(self):
return self.val.__repr__()
# Compute exponents and logs for all element of the Galois field
GF.EXP = [GF(0)]*512
GF.LOG = [GF(0)]*256
value = 1
for exponent in range(255):
GF.LOG[value] = GF(exponent)
GF.EXP[exponent] = GF(value)
value = ((value << 1) ^ 285) if value > 127 else value << 1
for i in range(255, 512):
GF.EXP[i] = GF.EXP[i-255].copy()
class Poly:
"""
Polynomial
Coefficients are in the order of largest to lowest degree:
ax^2 + bx + c -> coefs = [a, b, c]
"""
def __init__(self, coefs):
self.coefs = coefs.copy()
@property
def deg(self):
return len(self.coefs)
def copy(self):
return Poly(self.coefs)
# Addition
def __add__(self, p):
d1, d2 = self.deg, p.deg
deg = max(d1,d2)
result = [GF(0) for i in range(deg)]
for i in range(d1):
result[i + deg - d1] = self.coefs[i]
for i in range(d2):
result[i + deg - d2] += p.coefs[i]
return Poly(result)
# Multiplication
def __mul__(self, p):
result = [GF(0) for i in range(self.deg+p.deg-1)]
for i in range(p.deg):
for j in range(self.deg):
result[i+j] += self.coefs[j] * p.coefs[i]
return Poly(result)
# Division
def __truediv__(self, p):
dividend = self.coefs.copy()
dividend += [GF(0) for i in range(p.deg-1)]
quotient = []
for i in range(self.deg):
coef = dividend[i] / p.coefs[0]
quotient.append(coef)
for j in range(p.deg):
dividend[i+j] -= p.coefs[j] * coef
while dividend[0].val == 0:
dividend.pop(0)
return [Poly(quotient), Poly(dividend)]
# Representation -> string
def __repr__(self):
return f"<Poly {self.coefs}>"
# Inspired by nayuki's Creating a QR Code step by step
# bibtex key: nayuki_qr_js
# https://github.com/nayuki/Nayuki-web-published-code/blob/dfb110475327271e3b7279a432e2d1a1298815ad/creating-a-qr-code-step-by-step/creating-qr-code-steps.js
class History:
"""Widths history for mask evaluation, crit. 3"""
def __init__(self):
self.widths = [0]*7
self.widths[-1] = 4
self.colors = [0]*4
self.color = 0
# Add module to history, returns number of patterns found
def add(self, col):
s = 0
self.colors.append(col)
if col != self.color:
self.color = col
s = self.check()
self.widths.pop(0)
self.colors = self.colors[-sum(self.widths)-1:]
self.widths.append(0)
self.widths[-1] += 1
return s
# Check for patterns in the history
def check(self):
n = self.widths[1]
# Only black on white
if self.colors[self.widths[0]] != 1: return 0
# if 1:1:3:1:1
if n > 0 and self.widths[2] == n and self.widths[3] == n*3 and self.widths[4] == n and self.widths[5] == n:
# check if 4:1:1:3:1:1 + check if 1:1:3:1:1:4
return int(self.widths[0] >= 4) + int(self.widths[6] >= 4)
return 0
# Final check
def final(self):
for i in range(4):
self.add(0)
return self.check()
class QR:
TYPES = ["numeric", "alphanumeric", "byte", "kanji", "?"]
LEVELS = ["L","M","Q","H", "?"]
MODES = ["0001", "0010", "0100", "1000"]
ALPHANUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
VERSIONS = []
ERROR_CORRECTION = []
FINDER = ["1111111","1000001","1011101","1011101","1011101","1000001","1111111"]
FINDER = np.array([list(map(int, _)) for _ in FINDER])
ALIGNMENT_PATTERN_LOCATIONS = [
[],
[6, 18],
[6, 22],
[6, 26],
[6, 30],
[6, 34],
[6, 22, 38],
[6, 24, 42],
[6, 26, 46],
[6, 28, 50],
[6, 30, 54],
[6, 32, 58],
[6, 34, 62],
[6, 26, 46, 66],
[6, 26, 48, 70],
[6, 26, 50, 74],
[6, 30, 54, 78],
[6, 30, 56, 82],
[6, 30, 58, 86],
[6, 34, 62, 90],
[6, 28, 50, 72, 94],
[6, 26, 50, 74, 98],
[6, 30, 54, 78, 102],
[6, 28, 54, 80, 106],
[6, 32, 58, 84, 110],
[6, 30, 58, 86, 114],
[6, 34, 62, 90, 118],
[6, 26, 50, 74, 98, 122],
[6, 30, 54, 78, 102, 126],
[6, 26, 52, 78, 104, 130],
[6, 30, 56, 82, 108, 134],
[6, 34, 60, 86, 112, 138],
[6, 30, 58, 86, 114, 142],
[6, 34, 62, 90, 118, 146],
[6, 30, 54, 78, 102, 126, 150],
[6, 24, 50, 76, 102, 128, 154],
[6, 28, 54, 80, 106, 132, 158],
[6, 32, 58, 84, 110, 136, 162],
[6, 26, 54, 82, 110, 138, 166],
[6, 30, 58, 86, 114, 142, 170]
]
MASKS = [
lambda x,y: (x+y)%2 == 0,
lambda x,y: y%2 == 0,
lambda x,y: (x)%3 == 0,
lambda x,y: (x+y)%3 == 0,
lambda x,y: (y//2+x//3)%2 == 0,
lambda x,y: ((x*y)%2 + (x*y)%3) == 0,
lambda x,y: ((x*y)%2 + (x*y)%3)%2 == 0,
lambda x,y: ((x+y)%2 + (x*y)%3)%2 == 0
]
def __init__(self, data, level=0):
pygame.display.set_caption("QR Gen - Init")
log(f"Content: {data}")
log(f"EC Level: {self.LEVELS[level]}")
self.bits = ""
self.data = data
self.level = level
self.type = -1
self.version = -1
self.analyse_type()
self.compute_version()
self.build_char_count_indicator()
self.encode()
self.separate_codewords()
self.create_matrix()
def load_versions():
with open("qr_versions.txt", "r") as f:
versions = f.read().split("\n\n")
for v in versions:
lvls = [list(map(int, lvl.split("\t"))) for lvl in v.split("\n")]
QR.VERSIONS.append(lvls)
QR.VERSIONS = np.array(QR.VERSIONS)
def load_ec():
with open("error_correction.txt", "r") as f:
ecs = f.read().split("\n\n")
for ec in ecs:
lvls = [list(map(int, lvl.split("\t"))) for lvl in ec.split("\n")]
lvls = [lvl + [0]*(6-len(lvl)) for lvl in lvls]
QR.ERROR_CORRECTION.append(lvls)
QR.ERROR_CORRECTION = np.array(QR.ERROR_CORRECTION)
def __repr__(self):
return "<QR: {} - {} (V{})>".format(
QR.LEVELS[self.level],
QR.TYPES[self.type].title(),
"?" if self.version == -1 else self.version+1
)
def analyse_type(self):
pygame.display.set_caption("QR Gen - Type analysis")
if self.data.isnumeric():
self.type = 0
elif set(self.data).issubset(set(QR.ALPHANUM)):
self.type = 1
else:
try:
self.data.encode("ISO-8859-1")
self.type = 2
except:
self.type = 3
self.bits += self.MODES[self.type]
log(f"Type: {self.TYPES[self.type]}")
def compute_version(self):
pygame.display.set_caption("QR Gen - Version computation")
self.version = min(np.where(QR.VERSIONS[:, self.level, self.type] >= len(self.data))[0])
log(f"Version: {self.version+1}")
def get_char_count_len(self):
if 0 <= self.version < 9:
return [10,9,8,8][self.type]
elif 9 <= self.version < 26:
return [12,11,16,10][self.type]
elif 26 <= self.version < 40:
return [14,13,16,12][self.type]
def build_char_count_indicator(self):
pygame.display.set_caption("QR Gen - Char count ind")
length = self.get_char_count_len()
indicator = f"{{:0{length}b}}".format(len(self.data))
self.bits += indicator
log(f"Char count indicator: {indicator}")
def encode(self):
pygame.display.set_caption("QR Gen - Encoding")
if self.type == 0:
groups = [self.data[i:i+3] for i in range(0,len(self.data),3)]
for group in groups:
group = int(group)
sgroup = str(group)
if len(sgroup) == 3:
s = "{:010b}"
elif len(sgroup) == 2:
s = "{:07b}"
else:
s = "{:04b}"
self.bits += s.format(group)
elif self.type == 1:
data = self.data
last = None
if len(data)%2 == 1:
last = data[-1]
data = data[:-1]
for i in range(0, len(data), 2):
val1 = self.ALPHANUM.index(data[i])
val2 = self.ALPHANUM.index(data[i+1])
val = val1*45 + val2
self.bits += f"{val:011b}"
if not last is None:
self.bits += "{:06b}".format(self.ALPHANUM.index(last))
elif self.type == 2:
data = self.data.encode("ISO-8859-1")
self.bits += "".join(list(map("{:08b}".format, data)))
elif self.type == 3:
data = list(self.data.encode("shift_jis"))
#Combine double bytes
data = [data[i*2]<<8 | data[i*2+1] for i in range(len(data)//2)]
for dbyte in data:
if 0x8140 <= dbyte <= 0x9ffc:
dbyte = dbyte - 0x8140
elif 0xe040 <= dbyte <= 0xebbf:
dbyte = dbyte - 0xc140
msb = dbyte >> 8
lsb = dbyte & 0xff
val = msb * 0xc0 + lsb
self.bits += f"{val:013b}"
log(f"Encoded: {[self.bits[i:i+8] for i in range(0,len(self.bits),8)]}")
ec = self.ERROR_CORRECTION[self.version, self.level]
req_bits = ec[0]*8
#Terminator
self.bits += "0"*(min(4, req_bits-len(self.bits)))
#Pad to multiple of 8
if len(self.bits) % 8 != 0:
self.bits += "0"*(8-len(self.bits)%8)
#Pad to required bits
if len(self.bits) < req_bits:
for i in range((req_bits-len(self.bits))//8):
self.bits += ["11101100","00010001"][i%2]
log(f"Padded: {[self.bits[i:i+8] for i in range(0,len(self.bits),8)]}")
def separate_codewords(self):
pygame.display.set_caption("QR Gen - Separating codewords")
ec = self.ERROR_CORRECTION[self.version, self.level]
blocks = []
ec_codewords = []
codeword = 0
gen_poly = self.get_generator_poly(ec[1])
log(f"Gen poly: {gen_poly}")
#print(self.bits)
for i in range(ec[2]):
block = []
for j in range(ec[3]):
block.append(self.bits[codeword*8:codeword*8+8])
codeword += 1
blocks.append(block)
msg_poly = Poly(list(map(lambda b: GF(int(b,2)), block)))
log(f"Msg poly (1-{i}): {msg_poly}")
quotient, remainder = msg_poly / gen_poly
log(f"EC poly (1-{i}): {remainder}")
ec_cwds = [f"{c.val:08b}" for c in remainder.coefs]
ec_codewords.append(ec_cwds)
#If group 2
if ec[4] != 0:
for i in range(ec[4]):
block = []
for j in range(ec[5]):
block.append(self.bits[codeword*8:codeword*8+8])
codeword += 1
blocks.append(block)
msg_poly = Poly(list(map(lambda b: GF(int(b,2)), block)))
log(f"Msg poly (2-{i}): {msg_poly}")
quotient, remainder = msg_poly / gen_poly
log(f"EC poly (2-{i}): {remainder}")
ec_cwds = [f"{c.val:08b}" for c in remainder.coefs]
ec_codewords.append(ec_cwds)
self.final_data_bits = ""
if len(blocks) == 1:
dbits = "".join(["".join(block) for block in blocks])
ec_bits = "".join(["".join(cwd) for cwd in ec_codewords])
log(f"EC bits: {[ec_bits[i:i+8] for i in range(0,len(ec_bits),8)]}")
self.final_data_bits = dbits + ec_bits
else:
#Interleave data codewords
for i in range(max(ec[3], ec[5])):
for block in blocks:
if i < len(block):
self.final_data_bits += block[i]
#Interleave error correction codewords
for i in range(ec[1]):
for block in ec_codewords:
self.final_data_bits += block[i]
#Add remainder bits
if 1 <= self.version < 6:
self.final_data_bits += "0"*7
log(f"Add 7 remainder bits")
elif 13 <= self.version < 20 or 27 <= self.version < 34:
self.final_data_bits += "0"*3
log(f"Add 3 remainder bits")
elif 20 <= self.version < 27:
self.final_data_bits += "0"*4
log(f"Add 4 remainder bits")
print_bytes(self.final_data_bits)
def get_generator_poly(self, n):
poly = Poly([GF(1)])
for i in range(n):
poly *= Poly([GF(1), GF(2)**GF(i)])
return poly
def get_alignment_pattern_locations(self):
return QR.ALIGNMENT_PATTERN_LOCATIONS[self.version]
def create_matrix(self):
size = self.version*4+21
log(f"Size: {size}")
self.matrix = np.zeros([size, size])-1 #-1: empty | -0.5: reserved | 0: white | 1: black
pygame.display.set_caption("QR Gen - Matrix")
if STEPS & S_EMPTY: self.show(step=True)
#Add separator
self.matrix[0:8, 0:8] = 0
self.matrix[-8:, 0:8] = 0
self.matrix[0:8, -8:] = 0
pygame.display.set_caption("QR Gen - Separator")
if STEPS & S_SEP: self.show(step=True)
#Place finders
self.matrix[0:7, 0:7] = QR.FINDER
self.matrix[-7:, 0:7] = QR.FINDER
self.matrix[0:7, -7:] = QR.FINDER
pygame.display.set_caption("QR Gen - Finder patterns")
if STEPS & S_FINDER: self.show(step=True)
#Add alignment patterns
locations = self.get_alignment_pattern_locations()
log(f"Alignment patterns: {locations}")
if self.version > 0:
for y in locations:
for x in locations:
#Check if not overlapping with finders
if np.all(self.matrix[y-2:y+3, x-2:x+3] == -1):
self.matrix[y-2:y+3, x-2:x+3] = 1
self.matrix[y-1:y+2, x-1:x+2] = 0
self.matrix[y, x] = 1
pygame.display.set_caption("QR Gen - Alignment patterns")
if STEPS & S_ALIGN: self.show(step=True)
#Add timing patterns
timing_length = size-2*8
self.matrix[6, 8:-8] = np.resize([1,0],timing_length)
self.matrix[8:-8, 6] = np.resize([1,0],timing_length)
pygame.display.set_caption("QR Gen - Timing patterns")
if STEPS & S_TIMING: self.show(step=True)
#Add reserved areas
self.matrix[self.version*4+13,8] = 1 #Black module
self.matrix[:9, :9] = np.maximum(self.matrix[:9, :9], -0.5) #Top-left
self.matrix[-8:, 8] = np.maximum(self.matrix[-8:, 8], -0.5) #Bottom-left
self.matrix[8, -8:] = np.maximum(self.matrix[8, -8:], -0.5) #Top-right
if self.version >= 6:
self.matrix[-11:-8, :6] = -0.5
self.matrix[:6, -11:-8] = -0.5
pygame.display.set_caption("QR Gen - Reserved areas")
if STEPS & S_RESERVED: self.show(step=True)
#Place data
dir_ = -1 #-1 = up | 1 = down
x, y = size-1, size-1
i = 0
zigzag = 0
mask_area = self.matrix == -1
pygame.display.set_caption("QR Gen - Data layout")
print(self.matrix.tolist())
while x >= 0:
if self.matrix[y,x] == -1:
self.matrix[y,x] = self.final_data_bits[i]
i += 1
if STEPS & S_DATA:
if not (STEPS & S_BYTES) or i%8==0:
self.show()
time.sleep(0.01)
if ((dir_+1)/2 + zigzag)%2 == 0:
x -= 1
else:
y += dir_
x += 1
if y == -1 or y == size:
dir_ = -dir_
y += dir_
x -= 2
else:
zigzag = 1-zigzag
#Vertical timing pattern
if x == 6:
x -= 1
if STEPS & S_DATA: self.show(step=True)
score, mask, matrix = self.try_masks(mask_area)
self.matrix = np.where(mask_area, matrix, self.matrix)
pygame.display.set_caption("QR Gen - Mask")
if STEPS & S_MASK: self.show(step=True)
#Format string
format_str = f"{(5-self.level)%4:02b}{mask:03b}"
format_str += "0"*10
format_str.lstrip("0")
log(f"Format str: {format_str}")
gen_poly = 0b10100110111
format_poly = int(format_str,2)
while format_poly.bit_length() > 10:
g = gen_poly << (format_poly.bit_length()-gen_poly.bit_length())
format_poly ^= g
log(f"Remainder: {format_poly:b}")
format_data = int(format_str,2) + format_poly
format_data ^= 0b101010000010010
format_data = f"{format_data:015b}"
log(f"XORed: {format_data}")
for i in range(15):
y1, x1 = min(8,15-i), min(7,i)
if i >= 6:
x1 += 1
if i >= 9:
y1 -= 1
y2, x2 = self.matrix.shape[0]-i-1 if i < 7 else 8, 8 if i < 7 else self.matrix.shape[1]+i-15
self.matrix[y1, x1] = format_data[i]
self.matrix[y2, x2] = format_data[i]
#Version information
if self.version >= 6:
gen_poly = 0b1111100100101
version_info_poly = int(self.version+1)<<12
while version_info_poly.bit_length() > 12:
g = gen_poly << (version_info_poly.bit_length()-gen_poly.bit_length())
version_info_poly ^= g
version_info_data = ((self.version+1)<<12) + version_info_poly
version_info_data = f"{version_info_data:018b}"
ox1, oy1 = 5, self.matrix.shape[0]-9
ox2, oy2 = self.matrix.shape[1]-9, 5
for i in range(18):
self.matrix[oy1 - i%3, ox1 - i//3] = version_info_data[i]
self.matrix[oy2 - i//3, ox2 - i%3] = version_info_data[i]
def try_masks(self, mask_area):
best = [None,None,None] #score, i, matrix
for i in range(8):
mask = QR.MASKS[i]
mat = self.matrix.copy()
for y in range(self.matrix.shape[0]):
for x in range(self.matrix.shape[1]):
if mask_area[y,x] and mask(x,y):
mat[y,x] = 1-mat[y,x]
#Format string
format_str = f"{(5-self.level)%4:02b}{i:03b}"
format_str += "0"*10
format_str.lstrip("0")
gen_poly = 0b10100110111
format_poly = int(format_str,2)
while format_poly.bit_length() > 10:
g = gen_poly << (format_poly.bit_length()-gen_poly.bit_length())
format_poly ^= g
format_data = int(format_str,2) + format_poly
format_data ^= 0b101010000010010
format_data = f"{format_data:015b}"
for j in range(15):
y1, x1 = min(8,15-j), min(7,j)
if j >= 6:
x1 += 1
if j >= 9:
y1 -= 1
y2, x2 = mat.shape[0]-j-1 if j < 7 else 8, 8 if j < 7 else mat.shape[1]+j-15
mat[y1, x1] = format_data[j]
mat[y2, x2] = format_data[j]
score = self.evaluate(mat.copy(), i)
if best[0] is None or score < best[0]:
best = [score, i, mat]
return best
def evaluate(self, matrix, i):
score = 0
matrix = np.where(matrix < 0, 0, matrix)
s1, s2, s3, s4 = 0, 0, 0, 0
#Condition 1 (horizontal)
for y in range(matrix.shape[0]):
col, count = -1, 0
for x in range(matrix.shape[1]):
if matrix[y,x] != col:
count = 0
col = matrix[y,x]
count += 1
if count == 5:
score += 3
s1 += 3
elif count > 5:
score += 1
s1 += 1
#Condition 1 (vertical)
for x in range(matrix.shape[1]):
col, count = -1, 0
for y in range(matrix.shape[0]):
if matrix[y,x] != col:
count = 0
col = matrix[y,x]
count += 1
if count == 5:
score += 3
s1 += 3
elif count > 5:
score += 1
s1 += 1
#Condition 2
for y in range(matrix.shape[0]-1):
for x in range(matrix.shape[1]-1):
zone = matrix[y:y+2, x:x+2]
if np.all(zone == zone[0,0]):
score += 3
s2 += 3
#Condition 3 (horizontal)
for y in range(matrix.shape[0]):
hist = History()
for x in range(matrix.shape[1]):
s = hist.add(matrix[y,x])
score += s*40
s3 += s*40
s = hist.final()
score += s*40
s3 += s*40
#Condition 3 (vertical)
for x in range(matrix.shape[1]):
hist = History()
for y in range(matrix.shape[0]):
s = hist.add(matrix[y,x])
score += s*40
s3 += s*40
s = hist.final()
score += s*40
s3 += s*40
#Condition 4
total = matrix.shape[0]*matrix.shape[1]
dark = np.sum(matrix == 1)
percent = 100*dark//total
p1 = percent-(percent%5)
p2 = p1+5
p1, p2 = abs(p1-50)/5, abs(p2-50)/5
score += min(p1,p2)*10
s4 += min(p1,p2)*10
log(f"mask {i}: {s1} + {s2} + {s3} + {s4} = {score}")
return score
def show(self, pos=None, step=False):
global win
events = pygame.event.get()
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
pygame.image.save(win, "/tmp/qr.jpg")
m = ((self.matrix.copy()+2)%3)*127
mat = np.ones((m.shape[0]+8, m.shape[1]+8))*255
mat[4:-4, 4:-4] = m
if not pos is None:
mat[pos[1]+4, pos[0]+4] = 50
size = 15
if win is None:
win = pygame.display.set_mode([mat.shape[0]*size, mat.shape[0]*size])
win.fill((255,255,255))
for y in range(mat.shape[0]):
for x in range(mat.shape[1]):
col = mat[y, x]
col = (col, col, col)
pygame.draw.rect(win, col, [x*size, y*size, size, size])
if coords:
N = 6
space = (mat.shape[0]-8)/(N-1)
margin = 4*size
SIZE = (mat.shape[0]-8)*size
pygame.draw.lines(win, (0,0,0), True, [
(margin, margin),(margin+SIZE, margin),
(margin+SIZE, margin+SIZE),(margin, margin+SIZE)
])
for i in range(N):
n = int(round(space*i))
d = size * n
pygame.draw.line(win, (0,0,0), [margin+d, margin], [margin+d, margin-15])
pygame.draw.line(win, (0,0,0), [margin, margin+d], [margin-15, margin+d])
pygame.draw.line(win, (0,0,0), [margin+d, margin+SIZE], [margin+d, margin+SIZE+15])
pygame.draw.line(win, (0,0,0), [margin+SIZE, margin+d], [margin+SIZE+15, margin+d])
text = font.render(str(n), True, (0,0,0))
win.blit(text, [margin+d-text.get_width()/2, margin-30-text.get_height()/2])
win.blit(text, [margin-30-text.get_width()/2, margin+d-text.get_height()/2])
win.blit(text, [margin+d-text.get_width()/2, margin+SIZE+30-text.get_height()/2])
win.blit(text, [margin+SIZE+30-text.get_width()/2, margin+d-text.get_height()/2])
pygame.display.flip()
if step:
input("Press Enter to continue")
def print_bytes(bytes_, int_=False):
result = ""
for i in range(len(bytes_)//8):
if int_:
result += str(int(bytes_[i*8:i*8+8],2)) + " "
else:
result += bytes_[i*8:i*8+8] + " "
result += bytes_[-(len(bytes_)%8):]
print(result.strip())
QR.load_versions()
QR.load_ec()
if __name__ == "__main__":
np.set_printoptions(linewidth=200)
pygame.display.set_caption("QR Gen")
#qr = QR("8675309", 0)
#qr = QR("HELLO WORLD", 2)
qr = QR("Hello, World!", 1)
#qr = QR("茗荷", 2)
#qr = QR("Hello, world! How are you doing ? I'm doing great, thank you ! Today is quite a sunny day, isn't it ?", 3)
#qr = QR("https://aufildeverre.ch/", 3)
#qr = QR("QR Code Symbol", 1)
#qr = QR("Attention !", 3)
#qr = QR("Lycacode", 0)
print(qr)
pygame.display.set_caption("QR Gen - Final")
qr.show(step=False)
input("Press Enter to quit")
events = pygame.event.get()
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
pygame.image.save(win, "/tmp/qr.jpg")