|
import gradio as gr |
|
from PIL import Image |
|
import qrcode |
|
from pathlib import Path |
|
import requests |
|
import io |
|
import os |
|
from PIL import Image |
|
import numpy as np |
|
import cv2 |
|
from pyzxing import BarCodeReader |
|
from PIL import ImageOps, ImageEnhance, ImageFilter |
|
from huggingface_hub import hf_hub_download, snapshot_download |
|
from PIL import ImageEnhance |
|
import replicate |
|
from dotenv import load_dotenv |
|
|
|
|
|
load_dotenv() |
|
|
|
USERNAME = os.getenv("USERNAME") |
|
PASSWORD = os.getenv("PASSWORD") |
|
REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN") |
|
|
|
|
|
os.environ["REPLICATE_API_TOKEN"] = REPLICATE_API_TOKEN |
|
|
|
qrcode_generator = qrcode.QRCode( |
|
version=1, |
|
error_correction=qrcode.ERROR_CORRECT_H, |
|
box_size=10, |
|
border=4, |
|
) |
|
|
|
|
|
|
|
CONTROLNET_MODELS = { |
|
"QR Code Monster": "monster-labs/control_v1p_sd15_qrcode_monster/v2/", |
|
"QR Code": "DionTimmer/controlnet_qrcode-control_v1p_sd15", |
|
|
|
} |
|
|
|
DIFFUSION_MODELS = { |
|
"GhostMix": "digiplay/GhostMixV1.2VAE", |
|
"Stable v1.5": "Jiali/stable-diffusion-1.5", |
|
|
|
} |
|
|
|
|
|
loaded_controlnet = None |
|
loaded_pipe = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def adjust_image(image, brightness, contrast, saturation): |
|
if image is None: |
|
return None |
|
|
|
img = Image.fromarray(image) if isinstance(image, np.ndarray) else image |
|
|
|
if brightness != 1: |
|
img = ImageEnhance.Brightness(img).enhance(brightness) |
|
if contrast != 1: |
|
img = ImageEnhance.Contrast(img).enhance(contrast) |
|
if saturation != 1: |
|
img = ImageEnhance.Color(img).enhance(saturation) |
|
|
|
return np.array(img) |
|
|
|
def resize_for_condition_image(input_image: Image.Image, resolution: int): |
|
input_image = input_image.convert("RGB") |
|
W, H = input_image.size |
|
k = float(resolution) / min(H, W) |
|
H *= k |
|
W *= k |
|
H = int(round(H / 64.0)) * 64 |
|
W = int(round(W / 64.0)) * 64 |
|
img = input_image.resize((W, H), resample=Image.LANCZOS) |
|
return img |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def scan_qr_code(image): |
|
|
|
if isinstance(image, np.ndarray): |
|
image = Image.fromarray(image) |
|
|
|
|
|
gray_image = image.convert('L') |
|
|
|
|
|
np_image = np.array(gray_image) |
|
|
|
|
|
try: |
|
qr = qrcode.QRCode() |
|
qr.add_data('') |
|
qr.decode(gray_image) |
|
return qr.data.decode('utf-8') |
|
except Exception: |
|
pass |
|
|
|
|
|
try: |
|
qr_detector = cv2.QRCodeDetector() |
|
retval, decoded_info, points, straight_qrcode = qr_detector.detectAndDecodeMulti(np_image) |
|
if retval: |
|
return decoded_info[0] |
|
except Exception: |
|
pass |
|
|
|
|
|
try: |
|
reader = BarCodeReader() |
|
results = reader.decode(np_image) |
|
if results: |
|
return results[0].parsed |
|
except Exception: |
|
pass |
|
|
|
return None |
|
|
|
def invert_image(image): |
|
if image is None: |
|
return None |
|
if isinstance(image, np.ndarray): |
|
return 255 - image |
|
elif isinstance(image, Image.Image): |
|
return ImageOps.invert(image.convert('RGB')) |
|
else: |
|
raise ValueError("Unsupported image type") |
|
|
|
def invert_displayed_image(image): |
|
if image is None: |
|
return None |
|
inverted = invert_image(image) |
|
if isinstance(inverted, np.ndarray): |
|
return Image.fromarray(inverted) |
|
return inverted |
|
|
|
|
|
|
|
def inference( |
|
qr_code_content: str, |
|
prompt: str, |
|
negative_prompt: str, |
|
guidance_scale: float = 9.0, |
|
qr_conditioning_scale: float = 1.47, |
|
num_inference_steps: int = 20, |
|
seed: int = -1, |
|
image_resolution: int = 512, |
|
scheduler: str = "K_EULER", |
|
eta: float = 0.0, |
|
num_outputs: int = 1, |
|
low_threshold: int = 100, |
|
high_threshold: int = 200, |
|
guess_mode: bool = False, |
|
disable_safety_check: bool = False, |
|
): |
|
try: |
|
progress = gr.Progress() |
|
progress(0, desc="Generating QR code...") |
|
|
|
|
|
qr = qrcode.QRCode( |
|
version=1, |
|
error_correction=qrcode.constants.ERROR_CORRECT_H, |
|
box_size=10, |
|
border=4, |
|
) |
|
qr.add_data(qr_code_content) |
|
qr.make(fit=True) |
|
qr_image = qr.make_image(fill_color="black", back_color="white") |
|
|
|
|
|
temp_qr_path = "temp_qr.png" |
|
qr_image.save(temp_qr_path) |
|
|
|
progress(0.3, desc="Running inference...") |
|
|
|
|
|
num_outputs = max(1, min(num_outputs, 10)) |
|
|
|
|
|
seed = int(seed) if seed != -1 else None |
|
|
|
|
|
high_threshold = max(1, int(high_threshold)) |
|
|
|
|
|
input_dict = { |
|
"prompt": prompt, |
|
"qr_image": open(temp_qr_path, "rb"), |
|
"negative_prompt": negative_prompt, |
|
"guidance_scale": float(guidance_scale), |
|
"qr_conditioning_scale": float(qr_conditioning_scale), |
|
"num_inference_steps": int(num_inference_steps), |
|
"image_resolution": int(image_resolution), |
|
"scheduler": scheduler, |
|
"eta": float(eta), |
|
"num_outputs": num_outputs, |
|
"low_threshold": int(low_threshold), |
|
"high_threshold": high_threshold, |
|
"guess_mode": guess_mode, |
|
"disable_safety_check": disable_safety_check, |
|
} |
|
|
|
|
|
if seed is not None: |
|
input_dict["seed"] = seed |
|
|
|
|
|
output = replicate.run( |
|
"anotherjesse/multi-control:76d8414a702e66c84fe2e6e9c8cbdc12e53f950f255aae9ffa5caa7873b12de0", |
|
input=input_dict |
|
) |
|
|
|
progress(0.9, desc="Processing results...") |
|
|
|
|
|
response = requests.get(output[0]) |
|
img = Image.open(io.BytesIO(response.content)) |
|
|
|
|
|
os.remove(temp_qr_path) |
|
|
|
progress(1.0, desc="Done!") |
|
return img, seed if seed is not None else -1 |
|
except Exception as e: |
|
print(f"Error in inference: {str(e)}") |
|
return Image.new('RGB', (512, 512), color='white'), -1 |
|
|
|
|
|
|
|
def invert_init_image_display(image): |
|
if image is None: |
|
return None |
|
inverted = invert_image(image) |
|
if isinstance(inverted, np.ndarray): |
|
return Image.fromarray(inverted) |
|
return inverted |
|
|
|
def adjust_color_balance(image, r, g, b): |
|
|
|
image = image.convert('RGB') |
|
|
|
|
|
r_channel, g_channel, b_channel = image.split() |
|
|
|
|
|
r_channel = r_channel.point(lambda i: i + (i * r)) |
|
g_channel = g_channel.point(lambda i: i + (i * g)) |
|
b_channel = b_channel.point(lambda i: i + (i * b)) |
|
|
|
|
|
return Image.merge('RGB', (r_channel, g_channel, b_channel)) |
|
|
|
def apply_qr_overlay(image, original_qr, overlay, opacity): |
|
if not overlay or original_qr is None: |
|
return image |
|
|
|
|
|
original_qr = original_qr.resize(image.size) |
|
|
|
|
|
return Image.blend(image, original_qr, opacity) |
|
|
|
def apply_edge_enhancement(image, strength): |
|
if strength == 0: |
|
return image |
|
|
|
|
|
enhanced = image.filter(ImageFilter.EDGE_ENHANCE) |
|
|
|
|
|
return Image.blend(image, enhanced, strength / 5.0) |
|
|
|
|
|
css = """ |
|
h1, h2, h3, h4, h5, h6, p, li, ul, ol, a { |
|
text-align: left; |
|
} |
|
.centered-image { |
|
display: block; |
|
margin-left: auto; |
|
margin-right: auto; |
|
max-width: 100%; |
|
height: auto; |
|
} |
|
""" |
|
|
|
def login(username, password): |
|
if username == USERNAME and password == PASSWORD: |
|
return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(value="Login successful! You can now access the QR Code Art Generator tab.", visible=True) |
|
else: |
|
return gr.update(visible=False), gr.update(visible=True), gr.update(visible=True), gr.update(value="Invalid username or password. Please try again.", visible=True) |
|
|
|
|
|
with gr.Blocks(theme='Hev832/Applio', css=css, fill_width=True, fill_height=True) as blocks: |
|
generated_images = gr.State([]) |
|
|
|
with gr.Tab("Welcome"): |
|
with gr.Row(): |
|
with gr.Column(scale=2): |
|
gr.Markdown( |
|
""" |
|
<img src="https://cdn-uploads.huggingface.co/production/uploads/64740cf7485a7c8e1bd51ac9/29sj9LyPQItG5uBOO2x3r.webp" alt="UGD Logo" width="250" class="centered-image"> |
|
|
|
# Underground Digital's QR Code Art Generator |
|
|
|
## Transform Your QR Codes into Brand Masterpieces |
|
|
|
This cutting-edge tool empowers our creative team to craft visually stunning, |
|
on-brand QR codes that perfectly blend functionality with artistic expression. |
|
## How It Works: |
|
|
|
1. **Enter Your QR Code Content**: Start by inputting the URL or text for your QR code. |
|
2. **Craft Your Prompt**: Describe the artistic style or theme you envision for your QR code. |
|
3. **Fine-tune with Advanced Settings**: Adjust parameters to perfect your creation (see tips below). |
|
4. **Generate and Iterate**: Click 'Run' to create your art, then refine as needed. |
|
""" |
|
) |
|
|
|
with gr.Column(scale=1): |
|
|
|
with gr.Row(): |
|
gr.Markdown( |
|
""" |
|
Login below using the internal<br> |
|
username and password to access the full app.<br> |
|
|
|
Once logged in, a new tab will appear named<br> |
|
"QR Code Art Generator" allowing you to access. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
username = gr.Textbox(label="Username", placeholder="Enter your username", value="ugd") |
|
with gr.Row(): |
|
password = gr.Textbox(label="Password", type="password", placeholder="Enter your password", value="ugd!") |
|
with gr.Row(): |
|
login_button = gr.Button("Login", size="sm") |
|
login_message = gr.Markdown(visible=False) |
|
|
|
|
|
with gr.Tab("QR Code Art Generator", visible=False) as app_container: |
|
with gr.Row(): |
|
with gr.Column(): |
|
qr_code_content = gr.Textbox( |
|
label="QR Code Content", |
|
placeholder="Enter URL or text for your QR code", |
|
info="This is what your QR code will link to or display when scanned.", |
|
value="https://www.go-yamamoto.com/", |
|
lines=1, |
|
) |
|
|
|
prompt = gr.Textbox( |
|
label="Artistic Prompt", |
|
placeholder="Describe the style or theme for your QR code art (For best results, keep the prompt to 75 characters or less as seen below)", |
|
value="A high-res, photo-realistic minimalist rendering of Mount Fuji as a sharp, semi-realistic silhouette on the horizon. The mountain conveys strength and motion with clean, crisp lines and natural flow. Features detailed snow textures, subtle ridge highlights, and a powerful yet serene atmosphere. Emphasizes strength with clarity and precision in texture and light.", |
|
info="Describe the style or theme for your QR code art (For best results, keep the prompt to 75 characters or less as seen in the example)", |
|
lines=8, |
|
) |
|
negative_prompt = gr.Textbox( |
|
label="Elements to Avoid", |
|
placeholder="Describe what you don't want in the image", |
|
value="ugly, disfigured, low quality, blurry, nsfw, bad_pictures, poorly drawn, distorted, overexposed, flat shading, bad proportions, deformed, pixelated, messy details, lack of contrast, unrealistic textures, bad anatomy, rough edges, low resolution", |
|
info="List elements or styles you want to avoid in your QR code art.", |
|
lines=4, |
|
) |
|
|
|
run_btn = gr.Button("🎨 Create Your QR Art", variant="primary") |
|
|
|
with gr.Accordion(label="Needs Some Prompting Help?", open=False, visible=True): |
|
gr.Markdown( |
|
""" |
|
## 🌟 Tips for Spectacular Results: |
|
- Use concise details in your prompt to help the AI understand your vision. |
|
- Use negative prompts to avoid unwanted elements in your image. |
|
- Experiment with different ControlNet models and diffusion models to find the best combination for your prompt. |
|
## 🎭 Prompt Ideas to Spark Your Creativity: |
|
- "A serene Japanese garden with cherry blossoms and a koi pond" |
|
- "A futuristic cityscape with neon lights and flying cars" |
|
- "An abstract painting with swirling colors and geometric shapes" |
|
- "A vintage-style travel poster featuring iconic landmarks" |
|
Remember, the magic lies in the details of your prompt and the fine-tuning of your settings. |
|
Happy creating! |
|
""" |
|
) |
|
|
|
with gr.Accordion("Set Custom QR Code Colors", open=False, visible=False): |
|
bg_color = gr.ColorPicker( |
|
label="Background Color", |
|
value="#FFFFFF", |
|
info="Choose the background color for the QR code" |
|
) |
|
qr_color = gr.ColorPicker( |
|
label="QR Code Color", |
|
value="#000000", |
|
info="Choose the color for the QR code pattern" |
|
) |
|
invert_final_image = gr.Checkbox( |
|
label="Invert Final Image", |
|
value=False, |
|
info="Check this to invert the colors of the final image", |
|
visible=False, |
|
) |
|
with gr.Accordion("AI Model Selection", open=False, visible=False): |
|
controlnet_model_dropdown = gr.Dropdown( |
|
choices=list(CONTROLNET_MODELS.keys()), |
|
value="QR Code Monster", |
|
label="ControlNet Model", |
|
info="Select the ControlNet model for QR code generation" |
|
) |
|
diffusion_model_dropdown = gr.Dropdown( |
|
choices=list(DIFFUSION_MODELS.keys()), |
|
value="GhostMix", |
|
label="Diffusion Model", |
|
info="Select the main diffusion model for image generation" |
|
) |
|
|
|
|
|
with gr.Accordion(label="QR Code Image (Optional)", open=False, visible=False): |
|
qr_code_image = gr.Image( |
|
label="QR Code Image (Optional). Leave blank to automatically generate QR code", |
|
type="pil", |
|
) |
|
|
|
with gr.Column(): |
|
gr.Markdown("### Your Generated QR Code Art") |
|
result_image = gr.Image( |
|
label="Your Artistic QR Code", |
|
show_download_button=True, |
|
show_fullscreen_button=True, |
|
container=False |
|
) |
|
gr.Markdown("💾 Right-click and save the image to download your QR code art. **Note:** Images are currently not stored when generated, meaning each new generation deletes the previous one. Make sure to save your images as you go.") |
|
|
|
scan_button = gr.Button("Verify QR Code Works", visible=False) |
|
scan_result = gr.Textbox(label="Validation Result of QR Code", interactive=False, visible=False) |
|
used_seed = gr.Number(label="Seed Used", interactive=False) |
|
|
|
with gr.Accordion(label="Use Your Own Image as a Reference", open=True, visible=True) as init_image_acc: |
|
init_image = gr.Image(label="Reference Image", type="pil") |
|
with gr.Row(): |
|
use_qr_code_as_init_image = gr.Checkbox( |
|
label="Uncheck to use your own image for generation", |
|
value=True, |
|
interactive=True, |
|
info="Allows you to use your own image for generation, otherwise a generic QR Code is created automatically as the base image" |
|
) |
|
reference_image_strength = gr.Slider( |
|
minimum=0.0, |
|
maximum=5.0, |
|
step=0.05, |
|
value=0.6, |
|
label="Reference Image Influence", |
|
info="Controls how much the reference image influences the final result (0 = ignore, 5 = copy exactly)", |
|
visible=False |
|
) |
|
invert_init_image_button = gr.Button("Invert Init Image", size="sm", visible=False) |
|
|
|
with gr.Tab("Advanced Settings"): |
|
with gr.Accordion("Advanced Art Controls", open=True): |
|
with gr.Row(): |
|
qr_conditioning_scale = gr.Slider( |
|
minimum=0.0, |
|
maximum=5.0, |
|
step=0.01, |
|
value=1.47, |
|
label="QR Code Visibility", |
|
) |
|
with gr.Accordion("QR Code Visibility Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**QR Code Visibility** controls how prominent the QR code is in the final image: |
|
|
|
- **Low (0.0-1.0)**: QR code blends more with the art, potentially harder to scan. |
|
- **Medium (1.0-3.0)**: Balanced visibility, usually scannable while maintaining artistic quality. |
|
- **High (3.0-5.0)**: QR code stands out more, easier to scan but less artistic. |
|
|
|
Start with 1.47 for a good balance between art and functionality. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
guidance_scale = gr.Slider( |
|
minimum=0.1, |
|
maximum=30.0, |
|
step=0.1, |
|
value=9.0, |
|
label="Prompt Adherence", |
|
) |
|
with gr.Accordion("Prompt Adherence Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Prompt Adherence** determines how closely the AI follows your prompt: |
|
|
|
- **Low (0.1-5.0)**: More creative freedom, may deviate from prompt. |
|
- **Medium (5.0-15.0)**: Balanced between prompt and AI creativity. |
|
- **High (15.0-30.0)**: Strictly follows the prompt, less creative freedom. |
|
|
|
A value of 9.0 provides a good balance between creativity and prompt adherence. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
num_inference_steps = gr.Slider( |
|
minimum=1, |
|
maximum=100, |
|
step=1, |
|
value=20, |
|
label="Generation Steps", |
|
) |
|
with gr.Accordion("Generation Steps Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Generation Steps** affects the detail and quality of the generated image: |
|
|
|
- **Low (1-10)**: Faster generation, less detailed results. |
|
- **Medium (11-30)**: Good balance between speed and quality. |
|
- **High (31-100)**: More detailed results, slower generation. |
|
|
|
20 steps is a good starting point for most generations. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
image_resolution = gr.Slider( |
|
minimum=256, |
|
maximum=1024, |
|
step=64, |
|
value=512, |
|
label="Image Resolution", |
|
) |
|
with gr.Accordion("Image Resolution Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Image Resolution** determines the size and detail of the generated image: |
|
|
|
- **Low (256-384)**: Faster generation, less detailed. |
|
- **Medium (512-768)**: Good balance of detail and generation time. |
|
- **High (832-1024)**: More detailed, slower generation. |
|
|
|
512x512 is a good default for most use cases. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
seed = gr.Slider( |
|
minimum=-1, |
|
maximum=9999999999, |
|
step=1, |
|
value=-1, |
|
label="Generation Seed", |
|
) |
|
with gr.Accordion("Generation Seed Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Generation Seed** controls the randomness of the generation: |
|
|
|
- **-1**: Random seed each time, producing different results. |
|
- **Any positive number**: Consistent results for the same inputs. |
|
|
|
Use -1 to explore various designs, or set a specific seed to recreate a particular result. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
scheduler = gr.Dropdown( |
|
choices=["DDIM", "K_EULER", "DPMSolverMultistep", "K_EULER_ANCESTRAL", "PNDM", "KLMS"], |
|
value="K_EULER", |
|
label="Sampling Method", |
|
) |
|
with gr.Accordion("Sampling Method Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Sampling Method** affects the image generation process: |
|
|
|
- **K_EULER**: Good balance of speed and quality. |
|
- **DDIM**: Can produce sharper results but may be slower. |
|
- **DPMSolverMultistep**: Often produces high-quality results. |
|
- **K_EULER_ANCESTRAL**: Can introduce more variations. |
|
- **PNDM**: Another quality-focused option. |
|
- **KLMS**: Can produce smooth results. |
|
|
|
Experiment with different methods to find what works best for your specific prompts. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
eta = gr.Slider( |
|
minimum=0.0, |
|
maximum=1.0, |
|
step=0.01, |
|
value=0.0, |
|
label="ETA (Noise Level)", |
|
) |
|
with gr.Accordion("ETA Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**ETA (Noise Level)** controls the amount of noise in the generation process: |
|
|
|
- **0.0**: No added noise, more deterministic results. |
|
- **0.1-0.5**: Slight variations in output. |
|
- **0.6-1.0**: More variations, potentially more creative results. |
|
|
|
Start with 0.0 and increase if you want more variation in your outputs. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
low_threshold = gr.Slider( |
|
minimum=1, |
|
maximum=255, |
|
step=1, |
|
value=100, |
|
label="Edge Detection Low Threshold", |
|
) |
|
high_threshold = gr.Slider( |
|
minimum=1, |
|
maximum=255, |
|
step=1, |
|
value=200, |
|
label="Edge Detection High Threshold", |
|
) |
|
with gr.Accordion("Edge Detection Thresholds Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Edge Detection Thresholds** affect how the QR code edges are processed: |
|
|
|
- **Low Threshold**: Lower values detect more edges, higher values fewer. |
|
- **High Threshold**: Determines which edges are strong. Higher values result in fewer strong edges. |
|
|
|
Default values (100, 200) work well for most QR codes. Adjust if you need more or less edge definition. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
guess_mode = gr.Checkbox( |
|
label="Guess Mode", |
|
value=False, |
|
) |
|
with gr.Accordion("Guess Mode Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Guess Mode**, when enabled, allows the AI to interpret the input image more freely: |
|
|
|
- **Unchecked**: AI follows the QR code structure more strictly. |
|
- **Checked**: AI has more freedom to interpret the input, potentially leading to more creative results. |
|
|
|
Use this if you want more artistic interpretations of your QR code. |
|
""" |
|
) |
|
|
|
with gr.Row(): |
|
disable_safety_check = gr.Checkbox( |
|
label="Disable Safety Check", |
|
value=False, |
|
) |
|
with gr.Accordion("Safety Check Explanation", open=False): |
|
gr.Markdown( |
|
""" |
|
**Disable Safety Check** removes content filtering from the generation process: |
|
|
|
- **Unchecked**: Normal content filtering applied. |
|
- **Checked**: No content filtering, may produce unexpected or inappropriate results. |
|
|
|
Use with caution and only if necessary for your specific use case. |
|
""" |
|
) |
|
with gr.Tab("Image Editing"): |
|
with gr.Column(): |
|
image_selector = gr.Dropdown(label="Select Image to Edit", choices=[], interactive=True, visible=False) |
|
image_to_edit = gr.Image(label="Your Artistic QR Code", show_download_button=True, show_fullscreen_button=True, container=True) |
|
|
|
with gr.Row(): |
|
qr_overlay = gr.Checkbox(label="Overlay Original QR Code", value=False, visible=False) |
|
qr_opacity = gr.Slider(minimum=0.1, maximum=1.0, step=0.1, value=0.5, label="QR Overlay Opacity", visible=False) |
|
edge_enhance = gr.Slider(minimum=0.0, maximum=5.0, step=0.1, value=0.0, label="Edge Enhancement", visible=False) |
|
|
|
with gr.Row(): |
|
red_balance = gr.Slider(minimum=-1.0, maximum=1.0, step=0.1, value=0.0, label="Red Balance") |
|
green_balance = gr.Slider(minimum=-1.0, maximum=1.0, step=0.1, value=0.0, label="Green Balance") |
|
blue_balance = gr.Slider(minimum=-1.0, maximum=1.0, step=0.1, value=0.0, label="Blue Balance") |
|
|
|
|
|
with gr.Row(): |
|
brightness = gr.Slider(minimum=0.1, maximum=2.0, step=0.1, value=1.0, label="Brightness") |
|
contrast = gr.Slider(minimum=0.1, maximum=2.0, step=0.1, value=1.0, label="Contrast") |
|
saturation = gr.Slider(minimum=0.1, maximum=2.0, step=0.1, value=1.0, label="Saturation") |
|
with gr.Row(): |
|
invert_button = gr.Button("Invert Image", size="sm") |
|
|
|
with gr.Row(): |
|
edited_image = gr.Image(label="Edited QR Code", show_download_button=True, show_fullscreen_button=True, visible=False) |
|
scan_button = gr.Button("Verify QR Code Works", size="sm", visible=False) |
|
scan_result = gr.Textbox(label="Validation Result of QR Code", interactive=False, visible=False) |
|
|
|
used_seed = gr.Number(label="Seed Used", interactive=False) |
|
|
|
gr.Markdown( |
|
""" |
|
### 🔍 Analyzing Your Creation |
|
- Is the QR code scannable? Check with your phone camera to see if it can scan it. |
|
- If not scannable, use the Brightness, Contrast, and Saturation sliders to optimize the QR code for scanning. |
|
- Does the art style match your prompt? If not, try adjusting the 'Prompt Adherence'. |
|
- Want more artistic flair? Increase the 'Artistic Freedom'. |
|
- Need a clearer QR code? Raise the 'QR Code Visibility'. |
|
""" |
|
) |
|
|
|
def scan_and_display(image): |
|
if image is None: |
|
return "No image to scan" |
|
|
|
scanned_text = scan_qr_code(image) |
|
if scanned_text: |
|
return f"Scanned successfully: {scanned_text}" |
|
else: |
|
return "Failed to scan QR code. Try adjusting the settings for better visibility." |
|
|
|
def invert_displayed_image(image): |
|
if image is None: |
|
return None |
|
return invert_image(image) |
|
|
|
scan_button.click( |
|
scan_and_display, |
|
inputs=[result_image], |
|
outputs=[scan_result] |
|
) |
|
|
|
invert_button.click( |
|
invert_displayed_image, |
|
inputs=[result_image], |
|
outputs=[result_image] |
|
) |
|
|
|
invert_init_image_button.click( |
|
invert_init_image_display, |
|
inputs=[init_image], |
|
outputs=[init_image] |
|
) |
|
|
|
brightness.change( |
|
adjust_image, |
|
inputs=[result_image, brightness, contrast, saturation], |
|
outputs=[result_image] |
|
) |
|
contrast.change( |
|
adjust_image, |
|
inputs=[result_image, brightness, contrast, saturation], |
|
outputs=[result_image] |
|
) |
|
saturation.change( |
|
adjust_image, |
|
inputs=[result_image, brightness, contrast, saturation], |
|
outputs=[result_image] |
|
) |
|
|
|
|
|
def update_reference_image_strength_visibility(init_image, use_qr_code_as_init_image): |
|
return gr.update(visible=init_image is not None and not use_qr_code_as_init_image) |
|
|
|
init_image.change( |
|
update_reference_image_strength_visibility, |
|
inputs=[init_image, use_qr_code_as_init_image], |
|
outputs=[reference_image_strength] |
|
) |
|
|
|
use_qr_code_as_init_image.change( |
|
update_reference_image_strength_visibility, |
|
inputs=[init_image, use_qr_code_as_init_image], |
|
outputs=[reference_image_strength] |
|
) |
|
|
|
run_btn.click( |
|
fn=inference, |
|
inputs=[ |
|
qr_code_content, |
|
prompt, |
|
negative_prompt, |
|
guidance_scale, |
|
qr_conditioning_scale, |
|
num_inference_steps, |
|
seed, |
|
image_resolution, |
|
scheduler, |
|
eta, |
|
low_threshold, |
|
high_threshold, |
|
guess_mode, |
|
disable_safety_check, |
|
], |
|
outputs=[result_image, used_seed], |
|
concurrency_limit=20 |
|
) |
|
|
|
|
|
login_button.click( |
|
login, |
|
inputs=[username, password], |
|
outputs=[app_container, login_message, login_button, login_message] |
|
) |
|
|
|
|
|
password.submit( |
|
login, |
|
inputs=[username, password], |
|
outputs=[app_container, login_message, login_button, login_message] |
|
) |
|
|
|
|
|
|
|
|
|
blocks.queue(max_size=20) |
|
blocks.launch(share=False, show_api=False) |