Spaces:
Running on Zero
Running on Zero
| """Image processing utilities.""" | |
| import json | |
| import zipfile | |
| from pathlib import Path | |
| from typing import Optional, List, Dict, Any | |
| from datetime import datetime | |
| from PIL import Image | |
| import logging | |
| from config.settings import OUTPUT_DIR | |
| logger = logging.getLogger(__name__) | |
| def save_image( | |
| image: Image.Image, | |
| prompt: str, | |
| params: Dict[str, Any], | |
| metadata: Optional[Dict[str, Any]] = None | |
| ) -> Path: | |
| """Save an image with metadata. | |
| Args: | |
| image: PIL Image object to save. | |
| prompt: Prompt used to generate the image. | |
| params: Generation parameters. | |
| metadata: Additional metadata to include. | |
| Returns: | |
| Path to the saved image file. | |
| """ | |
| timestamp = datetime.now().timestamp() | |
| filename = f"texture_{int(timestamp)}.png" | |
| filepath = OUTPUT_DIR / filename | |
| # Save image | |
| image.save(filepath, "PNG") | |
| logger.info(f"Saved image to {filepath}") | |
| # Save metadata | |
| metadata_path = filepath.with_suffix(".json") | |
| metadata_dict = { | |
| "timestamp": timestamp, | |
| "prompt": prompt, | |
| "params": params, | |
| "image_path": str(filepath), | |
| "filename": filename, | |
| } | |
| if metadata: | |
| metadata_dict.update(metadata) | |
| with open(metadata_path, "w", encoding="utf-8") as f: | |
| json.dump(metadata_dict, f, indent=2) | |
| return filepath | |
| def create_thumbnail(image: Image.Image, size: tuple[int, int] = (256, 256)) -> Image.Image: | |
| """Create a thumbnail from an image. | |
| Args: | |
| image: PIL Image object. | |
| size: Thumbnail size (width, height). | |
| Returns: | |
| Thumbnail Image object. | |
| """ | |
| thumb = image.copy() | |
| thumb.thumbnail(size, Image.Resampling.LANCZOS) | |
| return thumb | |
| def validate_image_format(filepath: Path) -> bool: | |
| """Validate if a file is a valid image format. | |
| Args: | |
| filepath: Path to the image file. | |
| Returns: | |
| True if valid, False otherwise. | |
| """ | |
| valid_formats = {".png", ".jpg", ".jpeg", ".webp"} | |
| return filepath.suffix.lower() in valid_formats | |
| def create_zip(files: List[Path], output_path: Path) -> Path: | |
| """Create a ZIP archive from multiple files. | |
| Args: | |
| files: List of file paths to include. | |
| output_path: Path for the output ZIP file. | |
| Returns: | |
| Path to the created ZIP file. | |
| """ | |
| with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zipf: | |
| for file in files: | |
| if file.exists(): | |
| zipf.write(file, file.name) | |
| logger.info(f"Added {file.name} to ZIP") | |
| logger.info(f"Created ZIP archive at {output_path}") | |
| return output_path | |
| def optimize_image_for_web(image: Image.Image, max_size: int = 2048) -> Image.Image: | |
| """Optimize an image for web display. | |
| Args: | |
| image: PIL Image object. | |
| max_size: Maximum dimension size. | |
| Returns: | |
| Optimized Image object. | |
| """ | |
| width, height = image.size | |
| if width <= max_size and height <= max_size: | |
| return image | |
| # Calculate new dimensions maintaining aspect ratio | |
| if width > height: | |
| new_width = max_size | |
| new_height = int(height * (max_size / width)) | |
| else: | |
| new_height = max_size | |
| new_width = int(width * (max_size / height)) | |
| return image.resize((new_width, new_height), Image.Resampling.LANCZOS) | |
| def load_metadata(image_path: Path) -> Optional[Dict[str, Any]]: | |
| """Load metadata for an image. | |
| Args: | |
| image_path: Path to the image file. | |
| Returns: | |
| Metadata dictionary or None if not found. | |
| """ | |
| metadata_path = image_path.with_suffix(".json") | |
| if not metadata_path.exists(): | |
| return None | |
| try: | |
| with open(metadata_path, "r", encoding="utf-8") as f: | |
| return json.load(f) | |
| except Exception as e: | |
| logger.error(f"Error loading metadata: {e}") | |
| return None | |