from pathlib import Path from PIL import Image from PIL.PngImagePlugin import PngImageFile, PngInfo import json from pprint import pprint import argparse from rich.console import Console from rich.progress import Progress from rich_argparse import RichHelpFormatter def parse_a111(params, verbose=False): # params = [p.split(": ") for p in params.split("\n")] params = params.split("\n") prompt = params[0].strip() neg = params[1].split(":")[1].strip() settings = {} try: settings = { s.split(":")[0].strip(): s.split(":")[1].strip() for s in params[2].split(",") } except IndexError: settings = {"raw": params[2].strip()} if verbose: print(f"PROMPT: {prompt}") print(f"NEG: {neg}") print("SETTINGS:") pprint(settings, indent=4) return {"prompt": prompt, "negative": neg, "settings": settings} import glob if __name__ == "__main__": parser = argparse.ArgumentParser( description="Crude metadata extractor from A111 pngs", formatter_class=RichHelpFormatter ) parser.add_argument("inputs", nargs="*", help="Input image files") parser.add_argument("--output", help="Output JSON file") parser.add_argument("-v", "--verbose", action="store_true", help="Verbose mode") parser.add_argument( "--glob", help="Enable glob pattern matching", metavar="PATTERN" ) args = parser.parse_args() # - checks if not args.glob and not args.inputs: parser.error("Either --glob flag or inputs must be provided.") if args.glob: glob_pattern = args.glob try: pattern_path = str(Path(glob_pattern).expanduser().resolve()) if not any(glob.glob(pattern_path)): raise ValueError(f"No files found for glob pattern: {glob_pattern}") except Exception as e: console = Console() console.print( f"[bold red]Error: Invalid glob pattern '{glob_pattern}': {e}[/bold red]" ) exit(1) else: glob_pattern = None input_files = [] if glob_pattern: input_files = list(glob.glob(str(Path(glob_pattern).expanduser().resolve()))) else: input_files = [Path(p) for p in args.inputs] console = Console() console.print("Input Files:", style="bold", end=" ") console.print(f"{len(input_files):03d} files", style="cyan") # for input_file in args.inputs: # console.print(f"- {input_file}", style="cyan") console.print("\nOutput File:", style="bold", end=" ") console.print(f"{Path(args.output).resolve().absolute()}", style="cyan") with Progress(console=console, auto_refresh=True) as progress: # files = Path(pth).rglob("*.png") unique_info = {} last = None task = progress.add_task("[cyan]Extracting meta...", total=len(input_files) + 1) for p in input_files: im = Image.open(p) parsed = parse_a111(im.info["parameters"], args.verbose) if parsed != last: unique_info[Path(p).stem] = parsed last = parsed progress.update(task, advance=1) progress.refresh() unique_info = json.dumps(unique_info, indent=4) with open(args.output, "w") as f: f.write(unique_info) progress.update(task, advance=1) progress.refresh() console.print("\nProcessing completed!", style="bold green")