import sys import PIL.Image from mflux.callbacks.callback_manager import CallbackManager from mflux.config.config import Config from mflux.config.model_config import ModelConfig from mflux.controlnet.flux_controlnet import Flux1Controlnet from mflux.error.exceptions import PromptFileReadError, StopImageGenerationException from mflux.ui import defaults as ui_defaults from mflux.ui.cli.parsers import CommandLineParser from mflux.ui.prompt_utils import get_effective_prompt from mflux.ui.scale_factor import ScaleFactor def main(): # 0. Parse command line arguments parser = CommandLineParser(description="Upscale an image.") parser.add_general_arguments() parser.add_model_arguments(require_model_arg=False) parser.add_lora_arguments() parser.add_image_generator_arguments(supports_metadata_config=False, supports_dimension_scale_factor=True) parser.add_controlnet_arguments(require_image=True) parser.add_output_arguments() args = parser.parse_args() # 1. Load the model flux = Flux1Controlnet( model_config=ModelConfig.dev_controlnet_upscaler(), quantize=args.quantize, local_path=args.path, lora_paths=args.lora_paths, lora_scales=args.lora_scales, ) # 2. Register the optional callbacks memory_saver = CallbackManager.register_callbacks(args=args, flux=flux) try: # Calculate output dimensions and handle safety warnings width, height = _calculate_output_dimensions(args) for seed in args.seed: # 3. Generate an upscaled image for each seed value image = flux.generate_image( seed=seed, prompt=get_effective_prompt(args), controlnet_image_path=args.controlnet_image_path, config=Config( num_inference_steps=args.steps, height=height, width=width, controlnet_strength=args.controlnet_strength, ), ) # 4. Save the image image.save(path=args.output.format(seed=seed), export_json_metadata=args.metadata) except (StopImageGenerationException, PromptFileReadError) as exc: print(exc) finally: if memory_saver: print(memory_saver.memory_stats()) def _calculate_output_dimensions(args) -> tuple[int, int]: """Calculate output dimensions from args, handling scale factors and safety warnings.""" # Image.open is lazy/efficient, just need the dimension metadata orig_image = PIL.Image.open(args.controlnet_image_path) output_width, output_height = orig_image.size if isinstance(args.height, ScaleFactor): output_height: int = args.height.get_scaled_value(orig_image.height) # type: ignore else: output_height = args.height # type: ignore if isinstance(args.width, ScaleFactor): output_width: int = args.width.get_scaled_value(orig_image.width) # type: ignore else: output_width = args.width # type: ignore # Check if dimensions exceed safe limits total_pixels = output_height * output_width if total_pixels > ui_defaults.MAX_PIXELS_WARNING_THRESHOLD: print( f"⚠️ WARNING: The requested dimensions {output_width}x{output_height} " f"({total_pixels:,} pixels) exceed max recommended ({ui_defaults.MAX_PIXELS_WARNING_THRESHOLD:,} pixels)." ) print("This generation is likely to exceed the capabilities of this computer and may:") print(" ⏳ Take a very long time to complete") print(" 🔥 Run out of memory") print(" 💥 Cause the program and your Mac to crash") user_input = input("\nPress Enter to continue at your own risk, or type 'n' to cancel: ") if user_input.lower() in ["n", "no"]: print("🛑 Generation cancelled by user.") sys.exit(1) return output_width, output_height if __name__ == "__main__": main()