Last active
February 14, 2024 19:06
-
-
Save GorgeousOne/8058e050410b9f93923015a7deecb4b8 to your computer and use it in GitHub Desktop.
GUI for creating QR codes with a logo in the middle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
from tkinter import filedialog | |
import qrcode | |
from qrcode import constants as qr_const | |
from PIL import Image, ImageTk | |
import re | |
class MyGUI: | |
def __init__(self): | |
self.root = tk.Tk() | |
self.root.title("My GUI") | |
self.root.geometry("600x600") # Set the window size to 400x300 pixels | |
self.placeholder_img = Image.new("RGB", (300, 300), (255, 255, 255)) | |
self.qr_data = "" | |
self.qr_img = self.placeholder_img | |
self.logo_img = None | |
self.create_widgets() | |
def create_widgets(self): | |
self.data_label = tk.Label(self.root, text="Enter a string:") | |
self.data_label.pack() | |
self.data_entry = tk.Entry(self.root) | |
self.data_entry.pack() | |
self.data_entry.bind("<KeyRelease>", self.on_data_change) | |
self.radio_var = tk.StringVar() | |
self.radio_var.set(qr_const.ERROR_CORRECT_Q) # Set the default value | |
self.radio_label = tk.Label(self.root, text="Choose an error correction option:") | |
self.radio_label.pack() | |
self.radio_button1 = tk.Radiobutton(self.root, text="Low (7%)", variable=self.radio_var, value=qr_const.ERROR_CORRECT_L, command=self.update_qr_img) | |
self.radio_button1.pack() | |
self.radio_button2 = tk.Radiobutton(self.root, text="Medium (10%)", variable=self.radio_var, value=qr_const.ERROR_CORRECT_M, command=self.update_qr_img) | |
self.radio_button2.pack() | |
self.radio_button3 = tk.Radiobutton(self.root, text="Quartile (25%)", variable=self.radio_var, value=qr_const.ERROR_CORRECT_Q, command=self.update_qr_img) | |
self.radio_button3.pack() | |
self.radio_button4 = tk.Radiobutton(self.root, text="High (30%)", variable=self.radio_var, value=qr_const.ERROR_CORRECT_H, command=self.update_qr_img) | |
self.radio_button4.pack() | |
self.logo_size_label = tk.Label(self.root, text="Choose logo size:") | |
self.logo_size_label.pack() | |
self.logo_size_slider = tk.Scale(self.root, from_=4, to=13, orient=tk.HORIZONTAL, command=self.on_logo_size_change) | |
self.logo_size_slider.pack() | |
self.logo_size_slider.set(5) | |
self.logo_scale_label = tk.Label(self.root, text="Choose logo scale:") | |
self.logo_scale_label.pack() | |
self.logo_scale_slider = tk.Scale(self.root, from_=50, to=150, orient=tk.HORIZONTAL, resolution=5, command=self.on_logo_size_change) | |
self.logo_scale_slider.pack() | |
self.logo_scale_slider.set(100) | |
self.image_button = tk.Button(self.root, text="Load logo", command=self.load_image) | |
self.image_button.pack() | |
self.save_button = tk.Button(self.root, text="Save", command=self.save_qr_img) | |
self.save_button.pack() | |
thumbnail = ImageTk.PhotoImage(self.placeholder_img) | |
self.qr_label = tk.Label(self.root, image=thumbnail) | |
self.qr_label.image = thumbnail | |
self.qr_label.pack() | |
def update_qr_img(self): | |
if not self.qr_data: | |
self.qr_image = self.placeholder_img | |
return | |
code = qrcode.QRCode(error_correction=self.radio_var.get()) | |
code.add_data(self.qr_data) | |
code.make() | |
self.qr_img = code.make_image().convert('RGB') | |
self.update_display() | |
def update_display(self): | |
display_img = self.qr_img.copy() | |
#double the size of the qr code | |
if self.logo_img: | |
self.paste_logo(display_img) | |
# convert to tkinter image | |
thumbnail = ImageTk.PhotoImage(display_img) | |
self.qr_label.config(image=thumbnail) | |
self.qr_label.image = thumbnail | |
def paste_logo(self, qr_img): | |
pixel_size = 10 # size of qr code pixels "qrcode" generates | |
cutout_size = self.logo_size_slider.get() * pixel_size | |
# whiteout the logo area | |
qr_img.paste( | |
(255, 255, 255), | |
(qr_img.width//2 - cutout_size//2, | |
qr_img.height//2 - cutout_size//2, | |
qr_img.width//2 + cutout_size//2, | |
qr_img.height//2 + cutout_size//2)) | |
logo_scale = self.logo_scale_slider.get() / 100 | |
logo_size = int((cutout_size - 2 * pixel_size) * logo_scale) | |
# resize logo | |
relative_scale = logo_size / max(self.logo_img.width, self.logo_img.height) | |
scaled_logo = self.logo_img.resize(( | |
int(self.logo_img.width * relative_scale), | |
int(self.logo_img.height * relative_scale))) | |
# paste logo in the middle of the qr code | |
qr_img.paste(scaled_logo, ( | |
qr_img.width//2 - logo_size//2, | |
qr_img.height//2 - logo_size//2)) | |
def on_logo_size_change(self, *args): | |
self.update_display() | |
def on_data_change(self, *args): | |
# Get the string from the entry widget | |
self.qr_data = self.data_entry.get() | |
self.update_qr_img() | |
def load_image(self): | |
file_path = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")]) | |
# load PIL image | |
self.logo_img = Image.open(file_path) | |
self.update_display() | |
def save_qr_img(self): | |
file_path = filedialog.asksaveasfilename(filetypes=[("Image File", "*.png;*.jpg;*.jpeg")]) | |
if not re.search(r"\.(png|jpg|jpeg)$", file_path): | |
file_path += ".png" | |
final_img = self.qr_img.copy() | |
if self.logo_img: | |
self.paste_logo(final_img) | |
final_img.save(file_path) | |
def run(self): | |
self.root.mainloop() | |
if __name__ == "__main__": | |
gui = MyGUI() | |
gui.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment