Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -497,6 +497,118 @@ def generate_qr_codes(data: Union[str, Dict, List], combined: bool = True) -> Li
|
|
497 |
logger.error(f"QR code generation error: {e}")
|
498 |
return []
|
499 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
500 |
def create_modern_interface():
|
501 |
"""Create a modern and visually appealing Gradio interface"""
|
502 |
|
|
|
497 |
logger.error(f"QR code generation error: {e}")
|
498 |
return []
|
499 |
|
500 |
+
def create_qr_visualizer(qr_paths, metadata=None):
|
501 |
+
"""Create an interactive visualization of sequenced QR codes"""
|
502 |
+
if not qr_paths:
|
503 |
+
return None
|
504 |
+
|
505 |
+
# Extract metadata from QR codes if not provided
|
506 |
+
if metadata is None:
|
507 |
+
metadata = []
|
508 |
+
for path in qr_paths:
|
509 |
+
try:
|
510 |
+
img = Image.open(path)
|
511 |
+
qr = qrcode.QRCode()
|
512 |
+
data = qrcode.image.pil.PilImage.get_qr_data(img)
|
513 |
+
if data:
|
514 |
+
metadata.append(json.loads(data))
|
515 |
+
else:
|
516 |
+
# If can't extract, add placeholder
|
517 |
+
metadata.append({"chunk_index": len(metadata), "total_chunks": len(qr_paths)})
|
518 |
+
except Exception as e:
|
519 |
+
logger.error(f"Error extracting QR metadata: {e}")
|
520 |
+
metadata.append({"chunk_index": len(metadata), "total_chunks": len(qr_paths)})
|
521 |
+
|
522 |
+
# Compute optimal grid size
|
523 |
+
total_codes = len(qr_paths)
|
524 |
+
grid_size = math.ceil(math.sqrt(total_codes))
|
525 |
+
|
526 |
+
# Create a composite image with placeholders for disabled QR codes
|
527 |
+
def create_composite(enabled_indices):
|
528 |
+
# Size calculations for the grid
|
529 |
+
qr_size = 200 # Size of each QR code in pixels
|
530 |
+
padding = 20 # Padding between QR codes
|
531 |
+
|
532 |
+
# Create grid for visualization
|
533 |
+
grid_width = grid_size * (qr_size + padding) + padding
|
534 |
+
grid_height = grid_size * (qr_size + padding) + padding
|
535 |
+
|
536 |
+
# Create a white background image
|
537 |
+
composite = Image.new('RGBA', (grid_width, grid_height), (255, 255, 255, 255))
|
538 |
+
draw = ImageDraw.Draw(composite)
|
539 |
+
|
540 |
+
# Load and place QR codes on the grid
|
541 |
+
for i, path in enumerate(qr_paths):
|
542 |
+
# Calculate grid position
|
543 |
+
row = i // grid_size
|
544 |
+
col = i % grid_size
|
545 |
+
|
546 |
+
# Calculate pixel position
|
547 |
+
x = col * (qr_size + padding) + padding
|
548 |
+
y = row * (qr_size + padding) + padding
|
549 |
+
|
550 |
+
if i in enabled_indices:
|
551 |
+
try:
|
552 |
+
# Load and resize QR code
|
553 |
+
qr_img = Image.open(path)
|
554 |
+
qr_img = qr_img.resize((qr_size, qr_size), Image.Resampling.LANCZOS)
|
555 |
+
|
556 |
+
# Extract metadata for this QR
|
557 |
+
meta = metadata[i] if i < len(metadata) else {}
|
558 |
+
chunk_index = meta.get("chunk_index", i)
|
559 |
+
total_chunks = meta.get("total_chunks", len(qr_paths))
|
560 |
+
|
561 |
+
# Add visual indicator for sequence position
|
562 |
+
sequence_indicator = Image.new('RGBA', (qr_size, 30), (26, 54, 93, 200)) # Dark blue
|
563 |
+
draw_indicator = ImageDraw.Draw(sequence_indicator)
|
564 |
+
draw_indicator.text((10, 5), f"#{chunk_index+1} of {total_chunks}", fill=(255, 255, 255))
|
565 |
+
|
566 |
+
# Combine QR with indicator
|
567 |
+
qr_with_indicator = Image.new('RGBA', (qr_size, qr_size + 30))
|
568 |
+
qr_with_indicator.paste(qr_img, (0, 0))
|
569 |
+
qr_with_indicator.paste(sequence_indicator, (0, qr_size), sequence_indicator)
|
570 |
+
|
571 |
+
# Paste onto composite
|
572 |
+
composite.paste(qr_with_indicator, (x, y))
|
573 |
+
|
574 |
+
# Draw connection lines based on sequence
|
575 |
+
if i > 0:
|
576 |
+
prev_x = (col - 1) * (qr_size + padding) + padding if col > 0 else x
|
577 |
+
prev_y = (row * (qr_size + padding)) + padding
|
578 |
+
draw.line([(prev_x + qr_size // 2, prev_y + qr_size), (x + qr_size // 2, y)], fill=(0, 0, 0, 255), width=2)
|
579 |
+
|
580 |
+
return composite
|
581 |
+
|
582 |
+
# Create a toggleable interface for enabling/disabling QR codes
|
583 |
+
enabled_indices = list(range(total_codes)) # Start with all enabled
|
584 |
+
def toggle_qr(index):
|
585 |
+
if index in enabled_indices:
|
586 |
+
enabled_indices.remove(index)
|
587 |
+
else:
|
588 |
+
enabled_indices.append(index)
|
589 |
+
return create_composite(enabled_indices)
|
590 |
+
|
591 |
+
# Create the initial composite image
|
592 |
+
initial_composite = create_composite(enabled_indices)
|
593 |
+
|
594 |
+
# Display the composite image
|
595 |
+
plt.figure(figsize=(10, 10))
|
596 |
+
plt.imshow(initial_composite)
|
597 |
+
plt.axis('off')
|
598 |
+
plt.show()
|
599 |
+
|
600 |
+
return toggle_qr
|
601 |
+
|
602 |
+
# Integrate the visualizer into the main application
|
603 |
+
def visualize_qr_codes(qr_paths):
|
604 |
+
"""Visualize the generated QR codes with enable/disable functionality"""
|
605 |
+
toggle_function = create_qr_visualizer(qr_paths)
|
606 |
+
return toggle_function
|
607 |
+
|
608 |
+
# Add a button in the Gradio interface to trigger visualization
|
609 |
+
visualize_btn = gr.Button("🔍 Visualize QR Codes")
|
610 |
+
visualize_btn.click(visualize_qr_codes, inputs=output_gallery, outputs=None)
|
611 |
+
|
612 |
def create_modern_interface():
|
613 |
"""Create a modern and visually appealing Gradio interface"""
|
614 |
|