Custom QR Code GIF Background App

pipinstallpython@gmail.com

F(hits) + Value(1)


Dash application which allows a user to create a custom QR code, change color add an animated .GIF background and create something which stands out!

Imports

   from dash import *
import dash_bootstrap_components as dbc
import qrcode
from PIL import Image, ImageDraw
import base64
from io import BytesIO
import requests
import dash_mantine_components as dmc



Layout

layout = dbc.Container([
html.H1("QR Code Generator with GIF Background", className="text-center mt-4"),
dbc.Row([
dbc.Col([
dbc.Input(id="input-text", placeholder="Enter text/link for QR code", type="text", className="mb-2"),
dbc.Input(id="gif-url", placeholder="Enter URL for background GIF (optional)", type="text", className="mb-2"),
html.Div([
dmc.ColorPicker(id="qr-color-picker", format="rgba", value="rgba(0, 0, 0, 1)", fullWidth=True),
dmc.Space(h=10),
dmc.Text(id="selected-color"),
], className="mb-2"),
dbc.Input(id="qr-version", type="number", placeholder="QR Version (1-40)", min=1, max=40, value=2, className="mb-2"),
dbc.Input(id="qr-box-size", type="number", placeholder="Box Size", min=1, value=10, className="mb-2"),
dbc.Input(id="qr-border", type="number", placeholder="Border Size", min=0, value=4, className="mb-2"),
dbc.Input(id="qr-size-percent", type="number", placeholder="QR Size % of GIF", min=1, max=100, value=100, className="mb-2"),
dmc.Switch(
id="qr-transparent",
size="lg",
radius="sm",
label="Transparent QR Background",
checked=True,
className="mb-2"
),
dbc.Button("Generate QR Code", id="generate-button", color="primary", className="mt-2"),
], width=6, className="mx-auto"),
dbc.Col([
html.Div(id="qr-output", style={
"height": "300px",
"width": "300px",
"margin": "auto",
"display": "flex",
"justifyContent": "center",
"alignItems": "center",
"position": "relative",
}),
], width=6, className="text-center mt-4"),
], className="mt-4"),
])

Callbacks

@callback(Output("selected-color", "children"), Input("qr-color-picker", "value"))
def update_selected_color(color):
return f"Selected color: {color}"


@callback(
Output("qr-output", "children"),
Input("generate-button", "n_clicks"),
State("input-text", "value"),
State("gif-url", "value"),
State("qr-color-picker", "value"),
State("qr-version", "value"),
State("qr-box-size", "value"),
State("qr-border", "value"),
State("qr-size-percent", "value"),
State("qr-transparent", "checked"),
prevent_initial_call=True
)
def generate_qr_code(n_clicks, input_text, gif_url, qr_color, qr_version, qr_box_size, qr_border, qr_size_percent,
qr_transparent):
if not input_text:
return "Please enter text/link for QR code"

try:
# Create QR code
qr = qrcode.QRCode(version=qr_version, box_size=qr_box_size, border=qr_border)
qr.add_data(input_text)
qr.make(fit=True)

# Parse the RGBA color
r, g, b, a = [int(float(x)) for x in qr_color.strip('rgba()').split(',')]

# Get the QR code matrix
matrix = qr.get_matrix()

# Calculate the size of the QR code image
size = len(matrix) * qr_box_size

# Create a new image with white background
qr_img = Image.new('RGBA', (size, size), (255, 255, 255, 255))
draw = ImageDraw.Draw(qr_img)

# Draw QR code
for row in range(len(matrix)):
for col in range(len(matrix[row])):
if matrix[row][col]:
draw.rectangle(
[col * qr_box_size, row * qr_box_size,
(col + 1) * qr_box_size, (row + 1) * qr_box_size],
fill=(r, g, b, 255) # Use full opacity for QR code modules
)

if qr_transparent:
# If transparent, create a mask
mask = Image.new('L', qr_img.size, 0)
mask_draw = ImageDraw.Draw(mask)
for row in range(len(matrix)):
for col in range(len(matrix[row])):
if matrix[row][col]:
mask_draw.rectangle(
[col * qr_box_size, row * qr_box_size,
(col + 1) * qr_box_size, (row + 1) * qr_box_size],
fill=255
)
qr_img.putalpha(mask)

if gif_url:
# Fetch the background GIF
response = requests.get(gif_url)
gif = Image.open(BytesIO(response.content))

# Prepare to store all frames
frames = []

try:
for frame_index in range(gif.n_frames):
gif.seek(frame_index)
# Copy the current frame and convert to RGBA
frame = gif.copy().convert('RGBA')

# Resize QR code to fit within the GIF frame based on qr_size_percent
qr_size = int(min(frame.size) * (qr_size_percent / 100))
resized_qr = qr_img.resize((qr_size, qr_size), Image.LANCZOS)

# Calculate position to center the QR code
position = ((frame.width - qr_size) // 2, (frame.height - qr_size) // 2)

# Create a new frame with the GIF background and QR code overlay
new_frame = Image.new('RGBA', frame.size, (0, 0, 0, 0))
new_frame.paste(frame, (0, 0))
new_frame.paste(resized_qr, position, resized_qr if qr_transparent else None)

# Append the frame
frames.append(new_frame.convert('RGB'))

except EOFError:
pass # End of frames

# Save the resulting GIF
buffer = BytesIO()
frames[0].save(buffer, format="GIF", save_all=True, append_images=frames[1:],
loop=0, duration=gif.info.get('duration', 100))
else:
# If no GIF URL provided, just save the QR code as PNG
buffer = BytesIO()
qr_img.save(buffer, format="PNG")

# Encode the resulting image
buffer.seek(0)
encoded_image = base64.b64encode(buffer.getvalue()).decode('ascii')
result_image = f"data:image/{'gif' if gif_url else 'png'};base64,{encoded_image}"

# Return the resulting image
return html.Div([
html.Img(src=result_image, style={
"width": "300px",
"height": "300px",
"object-fit": "contain",
}),
html.A("Download Image", href=result_image, download=f"qr_code.{'gif' if gif_url else 'png'}",
className="mt-2 btn btn-primary")
])

except Exception as e:
return f"An error occurred: {str(e)}"