Spaces:
Sleeping
Sleeping
| import zipfile | |
| import tempfile | |
| import shutil | |
| from pathlib import Path | |
| from PIL import Image | |
| import uuid | |
| import os | |
| from src.helpers import check_webp_support | |
| # Check WebP support | |
| WEBP_SUPPORTED = check_webp_support() | |
| class ImageGallery: | |
| def __init__(self): | |
| self.uploaded_images = {} | |
| self.temp_dir = tempfile.mkdtemp() | |
| def add_generated_images(self, image_paths: list, prefix: str = "Generated"): | |
| """Add generated images to the gallery""" | |
| if not image_paths: | |
| return [], [], "" | |
| # Get current count for numbering | |
| current_count = len(self.uploaded_images) | |
| image_display_paths = [] | |
| choices = [] | |
| info_text = "" | |
| for i, image_path in enumerate(image_paths, 1): | |
| if not os.path.exists(image_path): | |
| continue | |
| # Generate unique ID for each image | |
| image_id = str(uuid.uuid4()) | |
| file_extension = Path(image_path).suffix.lower() | |
| # Copy to our temp directory | |
| temp_path = os.path.join(self.temp_dir, f"{image_id}{file_extension}") | |
| shutil.copy2(image_path, temp_path) | |
| # Handle WebP conversion if needed | |
| processed_path, processed_ext = self.convert_webp_if_needed(temp_path, image_id) | |
| # Get image info | |
| try: | |
| with Image.open(processed_path) as img: | |
| width, height = img.size | |
| file_size = os.path.getsize(processed_path) | |
| size_mb = file_size / (1024 * 1024) | |
| img_format = img.format | |
| except Exception as e: | |
| print(f"Error reading image info: {e}") | |
| width, height = "Unknown", "Unknown" | |
| size_mb = os.path.getsize(processed_path) / (1024 * 1024) if os.path.exists(processed_path) else 0 | |
| img_format = "Unknown" | |
| # Create display name | |
| display_index = current_count + i | |
| original_name = f"{prefix}_{i:02d}{file_extension}" | |
| # Store image info | |
| self.uploaded_images[image_id] = { | |
| 'path': processed_path, | |
| 'original_name': original_name, | |
| 'width': width, | |
| 'height': height, | |
| 'size_mb': size_mb, | |
| 'index': display_index, | |
| 'format': img_format | |
| } | |
| # Create display info | |
| format_info = f" [{img_format}]" if img_format != "Unknown" else "" | |
| display_name = f"#{display_index}: {original_name}{format_info}" | |
| image_display_paths.append((processed_path, display_name)) | |
| choices.append((f"#{display_index}: {original_name} ({width}x{height}, {size_mb:.1f}MB){format_info}", image_id)) | |
| # Add to info text | |
| info_text += f"#{display_index}: {original_name} - {img_format}\n" | |
| return image_display_paths, choices, info_text | |
| def get_current_gallery_state(self): | |
| """Get current gallery state for updating display""" | |
| if not self.uploaded_images: | |
| return [], [], "" | |
| image_paths = [] | |
| choices = [] | |
| info_text = "" | |
| # Sort by index | |
| sorted_images = sorted(self.uploaded_images.items(), key=lambda x: x[1]['index']) | |
| for image_id, image_info in sorted_images: | |
| format_info = f" [{image_info['format']}]" if image_info['format'] != "Unknown" else "" | |
| display_name = f"#{image_info['index']}: {image_info['original_name']}{format_info}" | |
| image_paths.append((image_info['path'], display_name)) | |
| choices.append((f"#{image_info['index']}: {image_info['original_name']} ({image_info['width']}x{image_info['height']}, {image_info['size_mb']:.1f}MB){format_info}", image_id)) | |
| info_text += f"#{image_info['index']}: {image_info['original_name']} - {image_info['format']}\n" | |
| return image_paths, choices, info_text | |
| def convert_webp_if_needed(self, file_path, image_id): | |
| """Convert WebP to PNG if there are compatibility issues""" | |
| try: | |
| with Image.open(file_path) as img: | |
| # If it's WebP and we want to ensure compatibility, convert to PNG | |
| if img.format == 'WEBP' and not WEBP_SUPPORTED: | |
| png_path = os.path.join(self.temp_dir, f"{image_id}_converted.png") | |
| # Convert RGBA if has transparency, otherwise RGB | |
| if img.mode in ('RGBA', 'LA'): | |
| img = img.convert('RGBA') | |
| else: | |
| img = img.convert('RGB') | |
| img.save(png_path, 'PNG') | |
| return png_path, '.png' | |
| else: | |
| return file_path, Path(file_path).suffix | |
| except Exception as e: | |
| print(f"Error processing image: {e}") | |
| return file_path, Path(file_path).suffix | |
| def upload_images(self, files): | |
| """Handle multiple image uploads with WebP support""" | |
| if not files: | |
| return [], [], "" | |
| self.uploaded_images.clear() | |
| image_paths = [] | |
| choices = [] | |
| info_text = "" | |
| for i, file in enumerate(files, 1): | |
| if file is None: | |
| continue | |
| # Generate unique ID for each image | |
| image_id = str(uuid.uuid4()) | |
| original_name = Path(file.name).name | |
| file_extension = Path(file.name).suffix.lower() | |
| try: | |
| # Copy file to temp directory with unique name | |
| temp_path = os.path.join(self.temp_dir, f"{image_id}{file_extension}") | |
| shutil.copy2(file.name, temp_path) | |
| # Handle WebP conversion if needed | |
| processed_path, processed_ext = self.convert_webp_if_needed(temp_path, image_id) | |
| # Get image info | |
| try: | |
| with Image.open(processed_path) as img: | |
| width, height = img.size | |
| file_size = os.path.getsize(processed_path) | |
| size_mb = file_size / (1024 * 1024) | |
| img_format = img.format | |
| except Exception as e: | |
| print(f"Error reading image info: {e}") | |
| width, height = "Unknown", "Unknown" | |
| size_mb = os.path.getsize(processed_path) / (1024 * 1024) if os.path.exists(processed_path) else 0 | |
| img_format = "Unknown" | |
| # Store image info | |
| self.uploaded_images[image_id] = { | |
| 'path': processed_path, | |
| 'original_name': original_name, | |
| 'width': width, | |
| 'height': height, | |
| 'size_mb': size_mb, | |
| 'index': i, | |
| 'format': img_format | |
| } | |
| # Create display info | |
| format_info = f" [{img_format}]" if img_format != "Unknown" else "" | |
| display_name = f"#{i}: {original_name}{format_info}" | |
| image_paths.append((processed_path, display_name)) | |
| choices.append((f"#{i}: {original_name} ({width}x{height}, {size_mb:.1f}MB){format_info}", image_id)) | |
| # Add to info text | |
| info_text += f"#{i}: {original_name} - {img_format}\n" | |
| except Exception as e: | |
| print(f"Error processing file {original_name}: {e}") | |
| # Still try to add it with basic info | |
| info_text += f"#{i}: {original_name} - ERROR: {str(e)}\n" | |
| continue | |
| return image_paths, choices, info_text | |
| def create_zip(self, selected_images): | |
| """Create zip file with selected images""" | |
| if not selected_images: | |
| return None | |
| # Create temporary zip file | |
| zip_path = os.path.join(self.temp_dir, f"selected_images_{uuid.uuid4().hex[:8]}.zip") | |
| with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
| for image_id in selected_images: | |
| if image_id in self.uploaded_images: | |
| image_info = self.uploaded_images[image_id] | |
| zipf.write( | |
| image_info['path'], | |
| image_info['original_name'] | |
| ) | |
| return zip_path if os.path.exists(zip_path) else None |