You've already forked amazing-qr
mirror of
https://github.com/x-hw/amazing-qr.git
synced 2025-08-10 22:41:23 +02:00
Recoded to be importable.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -93,3 +93,4 @@ ENV/
|
||||
.ropeproject
|
||||
|
||||
setup.py
|
||||
MANIFEST
|
120
MyQR/__main__.py
120
MyQR/__main__.py
@@ -1,120 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from MyQR.mylibs import theqrmodule
|
||||
from PIL import Image
|
||||
|
||||
# Alignment Pattern Locations
|
||||
alig_location = [
|
||||
(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)
|
||||
]
|
||||
|
||||
def combine(ver, qr_name, bg_name, colorized, contrast, brightness, save_place):
|
||||
from PIL import ImageEnhance, ImageFilter
|
||||
|
||||
qr = Image.open(qr_name)
|
||||
qr = qr.convert('RGBA') if colorized else qr
|
||||
|
||||
bg0 = Image.open(bg_name).convert('RGBA')
|
||||
con = contrast if contrast else 1.0
|
||||
bg0 = ImageEnhance.Contrast(bg0).enhance(con)
|
||||
bri = brightness if brightness else 1.0
|
||||
bg0 = ImageEnhance.Brightness(bg0).enhance(bri)
|
||||
|
||||
if bg0.size[0] < bg0.size[1]:
|
||||
bg0 = bg0.resize((qr.size[0]-24, (qr.size[0]-24)*int(bg0.size[1]/bg0.size[0])))
|
||||
else:
|
||||
bg0 = bg0.resize(((qr.size[1]-24)*int(bg0.size[0]/bg0.size[1]), qr.size[1]-24))
|
||||
|
||||
bg = bg0 if colorized else bg0.convert('1')
|
||||
|
||||
aligs = []
|
||||
if ver > 1:
|
||||
aloc = alig_location[ver-2]
|
||||
for a in range(len(aloc)):
|
||||
for b in range(len(aloc)):
|
||||
if not ((a==b==0) or (a==len(aloc)-1 and b==0) or (a==0 and b==len(aloc)-1)):
|
||||
for i in range(3*(aloc[a]-2), 3*(aloc[a]+3)):
|
||||
for j in range(3*(aloc[b]-2), 3*(aloc[b]+3)):
|
||||
aligs.append((i,j))
|
||||
|
||||
for i in range(qr.size[0]-24):
|
||||
for j in range(qr.size[1]-24):
|
||||
if not ((i in (18,19,20)) or (j in (18,19,20)) or (i<24 and j<24) or (i<24 and j>qr.size[1]-49) or (i>qr.size[0]-49 and j<24) or ((i,j) in aligs) or (i%3==1 and j%3==1) or (bg0.getpixel((i,j))[3]==0)):
|
||||
qr.putpixel((i+12,j+12), bg.getpixel((i,j)))
|
||||
|
||||
qr_name = os.path.join(save_place, os.path.splitext(os.path.basename(bg_name))[0] + '_qrcode.png')
|
||||
qr.resize((qr.size[0]*3, qr.size[1]*3)).save(qr_name)
|
||||
return qr_name
|
||||
|
||||
def run():
|
||||
import argparse
|
||||
argparser = argparse.ArgumentParser()
|
||||
argparser.add_argument('WORDs', help = 'The words to produce you QR-code picture, like a URL or a sentence. Please read the README file for the supported characters.')
|
||||
argparser.add_argument('-v', '--version', type = int, choices = range(1,41), help = 'The version means the length of a side of the QR-Code picture. From little size to large is 1 to 40.')
|
||||
argparser.add_argument('-l', '--level', choices = list('LMQH'), help = 'Use this argument to choose an Error-Correction-Level: L(Low), M(Medium) or Q(Quartile), H(High). Otherwise, just use the default one: H')
|
||||
argparser.add_argument('-p', '--picture', help = 'the picture e.g. example_pic.jpg')
|
||||
argparser.add_argument('-c', '--colorized', action = 'store_true', help = "Produce a colorized QR-Code with your picture. Just works when there is a correct '-p' or '--picture'.")
|
||||
argparser.add_argument('-con', '--contrast', type = float, help = 'A floating point value controlling the enhancement of contrast. Factor 1.0 always returns a copy of the original image, lower factors mean less color (brightness, contrast, etc), and higher values more. There are no restrictions on this value. Default: 1.0')
|
||||
argparser.add_argument('-bri', '--brightness', type = float, help = 'A floating point value controlling the enhancement of brightness. Factor 1.0 always returns a copy of the original image, lower factors mean less color (brightness, contrast, etc), and higher values more. There are no restrictions on this value. Default: 1.0')
|
||||
args = argparser.parse_args()
|
||||
|
||||
tempdir = os.path.join(os.path.expanduser('~'), '.myqr')
|
||||
|
||||
try:
|
||||
# the default version depends on WORDs and level
|
||||
# init as 0
|
||||
ver = args.version if args.version else 0
|
||||
# the default level is Q
|
||||
ecl = args.level if args.level else 'H'
|
||||
|
||||
if not os.path.exists(tempdir):
|
||||
os.makedirs(tempdir)
|
||||
|
||||
try:
|
||||
ver, qr_name = theqrmodule.get_qrcode(ver, ecl, args.WORDs, tempdir)
|
||||
except TypeError:
|
||||
qr_name = args.picture = None
|
||||
|
||||
if args.picture and args.picture[-4:]=='.gif':
|
||||
print('it takes a while, please wait for minutes...')
|
||||
|
||||
import imageio
|
||||
|
||||
im = Image.open(args.picture)
|
||||
im.save(os.path.join(tempdir, '0.png'))
|
||||
while True:
|
||||
try:
|
||||
seq = im.tell()
|
||||
im.seek(seq + 1)
|
||||
im.save(os.path.join(tempdir, '%s.png' %(seq+1)))
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
imsname = []
|
||||
for s in range(seq+1):
|
||||
bg_name = os.path.join(tempdir, '%s.png' % s)
|
||||
imsname.append(combine(ver, qr_name, bg_name, args.colorized, args.contrast, args.brightness, tempdir))
|
||||
|
||||
ims = [imageio.imread(pic) for pic in imsname]
|
||||
qr_name = os.path.splitext(os.path.basename(args.picture))[0] + '_qrcode.gif'
|
||||
imageio.mimsave(qr_name, ims)
|
||||
elif args.picture:
|
||||
qr_name = combine(ver, qr_name, args.picture, args.colorized, args.contrast, args.brightness, os.getcwd())
|
||||
elif qr_name:
|
||||
qr = Image.open(qr_name)
|
||||
qr_name = os.path.basename(qr_name)
|
||||
qr.resize((qr.size[0]*3, qr.size[1]*3)).save(qr_name)
|
||||
|
||||
if qr_name:
|
||||
print('Succeed! \nCheck out your ' +str(ver) + '-' + str(ecl) + ' QR-code at', os.path.abspath(qr_name))
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
import shutil
|
||||
if os.path.exists(tempdir):
|
||||
shutil.rmtree(tempdir)
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
run()
|
@@ -2,31 +2,21 @@
|
||||
|
||||
from MyQR.mylibs import data, ECC, structure, matrix, draw
|
||||
|
||||
supported_chars = r'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ·,.:;+-*/\~!@#$%^&`[]()?_{}|'
|
||||
|
||||
# ver: Version (from 0 to 40) 0 means default
|
||||
# ver: Version from 1 to 40
|
||||
# ecl: Error Correction Level (L,M,Q,H)
|
||||
# get a qrcode picture of 3*3 pixels per module
|
||||
def get_qrcode(ver, ecl, str, save_place):
|
||||
# ver == 0: default that is depending on str and ecl
|
||||
if ver not in range(41):
|
||||
print('WARNING: Version Error! Please choose a version from 0 to 40!')
|
||||
elif ecl not in 'LMQH':
|
||||
print('WARNING: Level Error! Please choose one of L,M,Q,H!')
|
||||
elif any(i not in supported_chars for i in str):
|
||||
print('WARNING: Input Error! Some characters are not supported.')
|
||||
else:
|
||||
# Data Coding
|
||||
ver, data_codewords = data.encode(ver, ecl, str)
|
||||
# Data Coding
|
||||
ver, data_codewords = data.encode(ver, ecl, str)
|
||||
|
||||
# Error Correction Coding
|
||||
ecc = ECC.encode(ver, ecl, data_codewords)
|
||||
# Error Correction Coding
|
||||
ecc = ECC.encode(ver, ecl, data_codewords)
|
||||
|
||||
# Structure final bits
|
||||
final_bits = structure.structure_final_bits(ver, ecl, data_codewords, ecc)
|
||||
# Structure final bits
|
||||
final_bits = structure.structure_final_bits(ver, ecl, data_codewords, ecc)
|
||||
|
||||
# Get the QR Matrix
|
||||
qrmatrix = matrix.get_qrmatrix(ver, ecl, final_bits)
|
||||
# Get the QR Matrix
|
||||
qrmatrix = matrix.get_qrmatrix(ver, ecl, final_bits)
|
||||
|
||||
# Draw the picture and Save it, then return the real ver and the absolute name
|
||||
return ver, draw.draw_qrcode(save_place, qrmatrix)
|
||||
# Draw the picture and Save it, then return the real ver and the absolute name
|
||||
return ver, draw.draw_qrcode(save_place, qrmatrix)
|
||||
|
140
MyQR/myqr.py
Normal file
140
MyQR/myqr.py
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from MyQR.mylibs import theqrmodule
|
||||
from PIL import Image
|
||||
|
||||
# Positional parameters
|
||||
# words: str
|
||||
#
|
||||
# Optional parameters
|
||||
# version: int, from 1 to 40
|
||||
# level: str, just one of ('L','M','Q','H')
|
||||
# picutre: str, a filename of a image
|
||||
# colorized: bool
|
||||
# constrast: float
|
||||
# brightness: float
|
||||
# save_name: str, the output filename like 'example.png'
|
||||
# save_dir: str, the output directory
|
||||
#
|
||||
# See [https://github.com/sylnsfar/qrcode] for more details!
|
||||
def run(words, version=1, level='H', picture=None, colorized=False, contrast=1.0, brightness=1.0, save_name=None, save_dir=os.getcwd()):
|
||||
|
||||
supported_chars = r'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ·,.:;+-*/\~!@#$%^&`[]()?_{}|'
|
||||
|
||||
# check every parameter
|
||||
if not isinstance(words, str) or any(i not in supported_chars for i in words):
|
||||
raise ValueError('Wrong words! Make sure the characters are supported!')
|
||||
if not isinstance(version, int) or version not in range(1, 41):
|
||||
raise ValueError('Wrong version! Please choose a int-type value from 1 to 40!')
|
||||
if not isinstance(level, str) or len(level)>1 or level not in 'LMQH':
|
||||
raise ValueError("Wrong level! Please choose a str-type level from {'L','M','Q','H'}!")
|
||||
if picture:
|
||||
if not isinstance(picture, str) or not os.path.isfile(picture) or picture[-4:] not in ('.jpg','.png','.bmp','.gif'):
|
||||
raise ValueError("Wrong picture! Input a filename that exists and be tailed with one of {'.jpg', '.png', '.bmp', '.gif'}!")
|
||||
if picture[-4:] == '.gif' and save_name and save_name[-4:] != '.gif':
|
||||
raise ValueError('Wrong save_name! If the picuter is .gif format, the output filename should be .gif format, too!')
|
||||
if not isinstance(colorized, bool):
|
||||
raise ValueError('Wrong colorized! Input a bool-type value!')
|
||||
if not isinstance(contrast, float):
|
||||
raise ValueError('Wrong contrast! Input a float-type value!')
|
||||
if not isinstance(brightness, float):
|
||||
raise ValueError('Wrong brightness! Input a float-type value!')
|
||||
if save_name and (not isinstance(save_name, str) or save_name[-4:] not in ('.jpg','.png','.bmp','.gif')):
|
||||
raise ValueError("Wrong save_name! Input a filename tailed with one of {'.jpg', '.png', '.bmp', '.gif'}!")
|
||||
if not os.path.isdir(save_dir):
|
||||
raise ValueError('Wrong save_dir! Input a existing-directory!')
|
||||
|
||||
|
||||
def combine(ver, qr_name, bg_name, colorized, contrast, brightness, save_dir, save_name=None):
|
||||
|
||||
# Alignment Pattern Locations
|
||||
alig_location = [
|
||||
(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)
|
||||
]
|
||||
|
||||
from PIL import ImageEnhance, ImageFilter
|
||||
|
||||
qr = Image.open(qr_name)
|
||||
qr = qr.convert('RGBA') if colorized else qr
|
||||
|
||||
bg0 = Image.open(bg_name).convert('RGBA')
|
||||
bg0 = ImageEnhance.Contrast(bg0).enhance(contrast)
|
||||
bg0 = ImageEnhance.Brightness(bg0).enhance(brightness)
|
||||
|
||||
if bg0.size[0] < bg0.size[1]:
|
||||
bg0 = bg0.resize((qr.size[0]-24, (qr.size[0]-24)*int(bg0.size[1]/bg0.size[0])))
|
||||
else:
|
||||
bg0 = bg0.resize(((qr.size[1]-24)*int(bg0.size[0]/bg0.size[1]), qr.size[1]-24))
|
||||
|
||||
bg = bg0 if colorized else bg0.convert('1')
|
||||
|
||||
aligs = []
|
||||
if ver > 1:
|
||||
aloc = alig_location[ver-2]
|
||||
for a in range(len(aloc)):
|
||||
for b in range(len(aloc)):
|
||||
if not ((a==b==0) or (a==len(aloc)-1 and b==0) or (a==0 and b==len(aloc)-1)):
|
||||
for i in range(3*(aloc[a]-2), 3*(aloc[a]+3)):
|
||||
for j in range(3*(aloc[b]-2), 3*(aloc[b]+3)):
|
||||
aligs.append((i,j))
|
||||
|
||||
for i in range(qr.size[0]-24):
|
||||
for j in range(qr.size[1]-24):
|
||||
if not ((i in (18,19,20)) or (j in (18,19,20)) or (i<24 and j<24) or (i<24 and j>qr.size[1]-49) or (i>qr.size[0]-49 and j<24) or ((i,j) in aligs) or (i%3==1 and j%3==1) or (bg0.getpixel((i,j))[3]==0)):
|
||||
qr.putpixel((i+12,j+12), bg.getpixel((i,j)))
|
||||
|
||||
qr_name = os.path.join(save_dir, os.path.splitext(os.path.basename(bg_name))[0] + '_qrcode.png') if not save_name else os.path.join(save_dir, save_name)
|
||||
qr.resize((qr.size[0]*3, qr.size[1]*3)).save(qr_name)
|
||||
return qr_name
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
tempdir = os.path.join(os.path.expanduser('~'), '.myqr')
|
||||
|
||||
try:
|
||||
if not os.path.exists(tempdir):
|
||||
os.makedirs(tempdir)
|
||||
|
||||
ver, qr_name = theqrmodule.get_qrcode(version, level, words, tempdir)
|
||||
|
||||
if picture and picture[-4:]=='.gif':
|
||||
import imageio
|
||||
|
||||
im = Image.open(picture)
|
||||
im.save(os.path.join(tempdir, '0.png'))
|
||||
while True:
|
||||
try:
|
||||
seq = im.tell()
|
||||
im.seek(seq + 1)
|
||||
im.save(os.path.join(tempdir, '%s.png' %(seq+1)))
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
imsname = []
|
||||
for s in range(seq+1):
|
||||
bg_name = os.path.join(tempdir, '%s.png' % s)
|
||||
imsname.append(combine(ver, qr_name, bg_name, colorized, contrast, brightness, tempdir))
|
||||
|
||||
ims = [imageio.imread(pic) for pic in imsname]
|
||||
qr_name = os.path.join(save_dir, os.path.splitext(os.path.basename(picture))[0] + '_qrcode.gif') if not save_name else os.path.join(save_dir, save_name)
|
||||
imageio.mimsave(qr_name, ims)
|
||||
elif picture:
|
||||
qr_name = combine(ver, qr_name, picture, colorized, contrast, brightness, save_dir, save_name)
|
||||
elif qr_name:
|
||||
qr = Image.open(qr_name)
|
||||
qr_name = os.path.join(save_dir, os.path.basename(qr_name)) if not save_name else os.path.join(save_dir, save_name)
|
||||
qr.resize((qr.size[0]*3, qr.size[1]*3)).save(qr_name)
|
||||
|
||||
return ver, level, qr_name
|
||||
|
||||
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
import shutil
|
||||
if os.path.exists(tempdir):
|
||||
shutil.rmtree(tempdir)
|
38
MyQR/terminal.py
Normal file
38
MyQR/terminal.py
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from MyQR.myqr import run
|
||||
import os
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
argparser = argparse.ArgumentParser()
|
||||
argparser.add_argument('Words', help = 'The words to produce you QR-code picture, like a URL or a sentence. Please read the README file for the supported characters.')
|
||||
argparser.add_argument('-v', '--version', type = int, choices = range(1,41), default = 1, help = 'The version means the length of a side of the QR-Code picture. From little size to large is 1 to 40.')
|
||||
argparser.add_argument('-l', '--level', choices = list('LMQH'), default = 'H', help = 'Use this argument to choose an Error-Correction-Level: L(Low), M(Medium) or Q(Quartile), H(High). Otherwise, just use the default one: H')
|
||||
argparser.add_argument('-p', '--picture', help = 'the picture e.g. example.jpg')
|
||||
argparser.add_argument('-c', '--colorized', action = 'store_true', help = "Produce a colorized QR-Code with your picture. Just works when there is a correct '-p' or '--picture'.")
|
||||
argparser.add_argument('-con', '--contrast', type = float, default = 1.0, help = 'A floating point value controlling the enhancement of contrast. Factor 1.0 always returns a copy of the original image, lower factors mean less color (brightness, contrast, etc), and higher values more. There are no restrictions on this value. Default: 1.0')
|
||||
argparser.add_argument('-bri', '--brightness', type = float, default = 1.0, help = 'A floating point value controlling the enhancement of brightness. Factor 1.0 always returns a copy of the original image, lower factors mean less color (brightness, contrast, etc), and higher values more. There are no restrictions on this value. Default: 1.0')
|
||||
argparser.add_argument('-n', '--name', help = "The filename of output tailed with one of {'.jpg', '.png', '.bmp', '.gif'}. eg. exampl.png")
|
||||
argparser.add_argument('-d', '--directory', default = os.getcwd(), help = 'The directory of output.')
|
||||
args = argparser.parse_args()
|
||||
|
||||
if args.picture and args.picture[-4:]=='.gif':
|
||||
print('It may take a while, please wait for minutes...')
|
||||
|
||||
try:
|
||||
ver, ecl, qr_name = run(
|
||||
args.Words,
|
||||
args.version,
|
||||
args.level,
|
||||
args.picture,
|
||||
args.colorized,
|
||||
args.contrast,
|
||||
args.brightness,
|
||||
args.name,
|
||||
args.directory
|
||||
)
|
||||
print('Succeed! \nCheck out your', str(ver) + '-' + str(ecl), 'QR-code:', qr_name)
|
||||
except:
|
||||
raise
|
Reference in New Issue
Block a user