Spaces:
Running
Running
| """ | |
| Module for extracting metadata from image files, particularly focusing on | |
| Stable Diffusion metadata from PNG files. | |
| """ | |
| import io | |
| from PIL import Image, PngImagePlugin | |
| import re | |
| class MetadataExtractor: | |
| """Class for extracting and parsing metadata from images.""" | |
| def extract_metadata(image_path): | |
| """ | |
| Extract metadata from an image file. | |
| Args: | |
| image_path: path to the image file | |
| Returns: | |
| dict: dictionary with extracted metadata | |
| """ | |
| try: | |
| # Open image with PIL | |
| image = Image.open(image_path) | |
| # Extract metadata from PNG info | |
| metadata_text = image.info.get("parameters", "") | |
| # Parse the metadata | |
| parsed_metadata = MetadataExtractor.parse_metadata(metadata_text) | |
| # Add basic image info | |
| parsed_metadata.update({ | |
| 'width': image.width, | |
| 'height': image.height, | |
| 'format': image.format, | |
| 'mode': image.mode, | |
| }) | |
| return parsed_metadata | |
| except Exception as e: | |
| print(f"Error extracting metadata from {image_path}: {e}") | |
| return {'error': str(e)} | |
| def parse_metadata(metadata_text): | |
| """ | |
| Parse Stable Diffusion metadata text into structured data. | |
| Args: | |
| metadata_text: raw metadata text from image | |
| Returns: | |
| dict: structured metadata | |
| """ | |
| if not metadata_text: | |
| return {'raw_text': ''} | |
| result = {'raw_text': metadata_text} | |
| # Extract prompt | |
| prompt_end = metadata_text.find("Negative prompt:") | |
| if prompt_end > 0: | |
| result['prompt'] = metadata_text[:prompt_end].strip() | |
| negative_prompt_end = metadata_text.find("\n", prompt_end) | |
| if negative_prompt_end > 0: | |
| result['negative_prompt'] = metadata_text[prompt_end + len("Negative prompt:"):negative_prompt_end].strip() | |
| else: | |
| result['prompt'] = metadata_text.strip() | |
| # Extract model name | |
| model_match = re.search(r'Model: ([^,\n]+)', metadata_text) | |
| if model_match: | |
| result['model'] = model_match.group(1).strip() | |
| # Extract other parameters | |
| params = { | |
| 'steps': r'Steps: (\d+)', | |
| 'sampler': r'Sampler: ([^,\n]+)', | |
| 'cfg_scale': r'CFG scale: ([^,\n]+)', | |
| 'seed': r'Seed: ([^,\n]+)', | |
| 'size': r'Size: ([^,\n]+)', | |
| 'model_hash': r'Model hash: ([^,\n]+)', | |
| } | |
| for key, pattern in params.items(): | |
| match = re.search(pattern, metadata_text) | |
| if match: | |
| result[key] = match.group(1).strip() | |
| return result | |
| def group_images_by_model(metadata_list): | |
| """ | |
| Group images by model name. | |
| Args: | |
| metadata_list: list of (image_path, metadata) tuples | |
| Returns: | |
| dict: dictionary with model names as keys and lists of image paths as values | |
| """ | |
| result = {} | |
| for image_path, metadata in metadata_list: | |
| model = metadata.get('model', 'unknown') | |
| if model not in result: | |
| result[model] = [] | |
| result[model].append(image_path) | |
| return result | |
| def group_images_by_prompt(metadata_list): | |
| """ | |
| Group images by prompt. | |
| Args: | |
| metadata_list: list of (image_path, metadata) tuples | |
| Returns: | |
| dict: dictionary with prompts as keys and lists of image paths as values | |
| """ | |
| result = {} | |
| for image_path, metadata in metadata_list: | |
| prompt = metadata.get('prompt', 'unknown') | |
| # Use first 50 chars as key to avoid extremely long keys | |
| prompt_key = prompt[:50] + ('...' if len(prompt) > 50 else '') | |
| if prompt_key not in result: | |
| result[prompt_key] = [] | |
| result[prompt_key].append((image_path, metadata.get('model', 'unknown'))) | |
| return result | |
| def update_metadata(image_path, new_metadata, output_path=None): | |
| """ | |
| Update metadata in an image file. | |
| Args: | |
| image_path: path to the input image file | |
| new_metadata: new metadata text to write | |
| output_path: path to save the updated image (if None, overwrites input) | |
| Returns: | |
| bool: True if successful, False otherwise | |
| """ | |
| try: | |
| # Open image with PIL | |
| image = Image.open(image_path) | |
| # Create a PngInfo object to store metadata | |
| pnginfo = PngImagePlugin.PngInfo() | |
| pnginfo.add_text("parameters", new_metadata) | |
| # Save the image with the updated metadata | |
| save_path = output_path if output_path else image_path | |
| image.save(save_path, format="PNG", pnginfo=pnginfo) | |
| return True | |
| except Exception as e: | |
| print(f"Error updating metadata: {e}") | |
| return False | |