File size: 3,552 Bytes
ddce00f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import qrcode
import numpy as np
from PIL import Image
import base64

correction_map = {
  'L': qrcode.constants.ERROR_CORRECT_L,
  'M': qrcode.constants.ERROR_CORRECT_M,
  'Q': qrcode.constants.ERROR_CORRECT_Q,
  'H': qrcode.constants.ERROR_CORRECT_H,
}

backgrounds = ['white', 'black', 'gray', 'noise']

bg_map = {
    'white': 255,
    'black': 0,
    'gray': 128,
}

def create_code(text, module_size, margin, background, error_correction, centered, submodule_prop, split=False):
  qr = qrcode.QRCode(
    version=1,
    error_correction=correction_map[error_correction],
    box_size=module_size,
    border=margin if margin > 0 else 1,
  )
  qr.add_data(text)
  qr.make(fit=True)

  img = qr.make_image(fill_color="black", back_color="white")

  # find smallest image size multiple of 256 that can fit qr
  offset_min = 8 * module_size
  w, h = img.size

  mask = None

  if margin == 0:
    corner_size = 9 * module_size
    # make a mask that hides the margin when not in the corners
    mask = np.ones((h, w)).astype(bool)
    mask[corner_size:-corner_size, :] = False
    mask[:, corner_size:-corner_size] = False
    mask[-corner_size:, -corner_size:] = False
    mask[module_size:-module_size, module_size:-module_size] = True

  if submodule_prop != 1:
    submodule_size = round(module_size * submodule_prop)
    k = (module_size - submodule_size) // 2
    # qr_array = np.array(img).reshape((h // module_size, w // module_size, module_size, module_size))
    new_mask = np.zeros((h // module_size, module_size, w // module_size, module_size)).astype(bool)
    new_mask[:, k:k+submodule_size, :, k:k+submodule_size] = True
    mask = np.logical_and(mask, new_mask.reshape((h, w)))

  w = (w + 255 + offset_min) // 256 * 256
  h = (h + 255 + offset_min) // 256 * 256

  # create new image with background chosen by user
  if background == 'noise':
    # noise = np.random.randint(0, 256, (h // module_size, w // module_size), dtype=np.uint8)
    noise = np.random.normal(128, 64, (h // module_size, w // module_size)).astype(np.uint8)
    # noise = (noise // 128) * 255
    noise = np.round(noise / 128) * 128
    # clamp values
    noise = np.clip(noise, 0, 255)
    
    bg = Image.fromarray(noise.astype(np.uint8)).resize((w, h), Image.NEAREST)
  else:
    bg = Image.new('L', (w, h), bg_map[background])

  # paste qr code in the center of the image
  if centered:
    coords = ((w - img.size[0]) // 2, (h - img.size[1]) // 2)
  else:
    # paste it aligned on module size, closest to center
    coords = ((w - img.size[0]) // 2 // module_size * module_size, (h - img.size[1]) // 2 // module_size * module_size)

  if mask is not None:
    new_img = Image.new('L', img.size, bg_map['gray'] if background == 'noise' else bg_map[background])
    new_img.paste(img, mask=Image.fromarray(mask))
    bg.paste(new_img, coords)
  else:
    bg.paste(img, coords)

  if split:
    # isolate the 3 qr markers, paste them onto a new gray image
    m_size = module_size * 9

    new_bg = Image.new('L', (w, h), bg_map['gray'])

    # create mask for the 3 markers from a numpy array
    mask = np.zeros((h, w), dtype=bool)
    mask[coords[1]:coords[1] + m_size, coords[0]:coords[0] + m_size] = True
    mask[coords[1]:coords[1] + m_size, coords[0] + img.size[0] - m_size:coords[0] + img.size[0]] = True
    mask[coords[1] + img.size[1] - m_size:coords[1] + img.size[1], coords[0]:coords[0] + m_size] = True

    # paste the 3 markers on the new image
    new_bg.paste(bg, mask=Image.fromarray(mask))

    return bg, new_bg
  else:
    return bg,